From 1dc34fd45cead8a1b4342b58c98b81441a1cb9ac Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Mon, 19 Aug 2024 11:03:27 +0000 Subject: [PATCH 01/71] Update cross build installation mechanism --- pyodide_build/build_env.py | 54 +++++++++++++--- pyodide_build/buildpkg.py | 15 ++--- pyodide_build/pypabuild.py | 93 ++++++++++++++++++++++++--- pyodide_build/tests/test_xbuildenv.py | 27 -------- pyodide_build/vendor/_pypabuild.py | 45 +++++++++++++ pyodide_build/xbuildenv.py | 49 +------------- 6 files changed, 182 insertions(+), 101 deletions(-) diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py index 5a19619a..1d18474e 100644 --- a/pyodide_build/build_env.py +++ b/pyodide_build/build_env.py @@ -129,7 +129,6 @@ def get_build_environment_vars(pyodide_root: Path) -> dict[str, str]: "PYODIDE": "1", # This is the legacy environment variable used for the aforementioned purpose "PYODIDE_PACKAGE_ABI": "1", - "PYTHONPATH": env["HOSTSITEPACKAGES"], } ) @@ -169,24 +168,63 @@ def get_hostsitepackages() -> str: @functools.cache -def get_unisolated_packages() -> list[str]: +def get_unisolated_packages() -> dict[str, str]: + """ + Get a list of unisolated packages. + Unisolated packages are packages that are often used during the build process + and have some platform-specific files. When these packages are required during + the build process, we switch some files to platform-specific ones. + + Returns + ------- + A dictionary of package names and versions. + """ + PYODIDE_ROOT = get_pyodide_root() - unisolated_file = PYODIDE_ROOT / "unisolated.txt" - if unisolated_file.exists(): - # in xbuild env, read from file - unisolated_packages = unisolated_file.read_text().splitlines() + if in_xbuildenv(): + unisolated_file = PYODIDE_ROOT / ".." / "requirements.txt" + unisolated_packages = {} + for line in unisolated_file.read_text().splitlines(): + name, version = line.split("==") + unisolated_packages[name] = version else: - unisolated_packages = [] + unisolated_packages = {} recipe_dir = PYODIDE_ROOT / "packages" recipes = load_all_recipes(recipe_dir) for name, config in recipes.items(): if config.build.cross_build_env: - unisolated_packages.append(name) + unisolated_packages[name] = config.package.version return unisolated_packages +def get_unisolated_files(package_name: str) -> tuple[Path, list[str]]: + """ + Get a list of unisolated files for a package. + + Parameters + ---------- + package_name + The name of the package + + Returns + ------- + A tuple of the package directory and a list of file paths relative to the package directory. + """ + PYODIDE_ROOT = get_pyodide_root() + + # TODO: unify libdir for in-tree and out-of-tree builds + if in_xbuildenv(): + libdir = PYODIDE_ROOT / ".." / "site-packages-extras" + else: + libdir = get_hostsitepackages() + + package_dir = libdir / package_name + return libdir, [str(f.relative_to(libdir)) for f in package_dir.rglob("*")] + + + def platform() -> str: emscripten_version = get_build_flag("PYODIDE_EMSCRIPTEN_VERSION") version = emscripten_version.replace(".", "_") diff --git a/pyodide_build/buildpkg.py b/pyodide_build/buildpkg.py index 312a66f1..705129f1 100755 --- a/pyodide_build/buildpkg.py +++ b/pyodide_build/buildpkg.py @@ -460,17 +460,14 @@ def _package_wheel( Path(self.build_args.host_install_dir) / f"lib/{python_dir}/site-packages" ) - if self.build_metadata.cross_build_env: - subprocess.run( - ["pip", "install", "-t", str(host_site_packages), f"{name}=={ver}"], - check=True, - ) + # Copy cross build files to host site packages for cross_build_file in self.build_metadata.cross_build_files: - shutil.copy( - (wheel_dir / cross_build_file), - host_site_packages / cross_build_file, - ) + src_file = wheel_dir / cross_build_file + dest_file = host_site_packages / cross_build_file + dest_file.parent.mkdir(parents=True, exist_ok=True) + + shutil.copy(src_file, dest_file) try: test_dir = self.src_dist_dir / "tests" diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index f6e5aff9..b84bf62b 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -21,6 +21,7 @@ get_hostsitepackages, get_pyversion, get_unisolated_packages, + get_unisolated_files, platform, ) from .io import _BuildSpecExports @@ -30,6 +31,7 @@ _error, _handle_build_error, _ProjectBuilder, + _get_venv_paths, ) AVOIDED_REQUIREMENTS = [ @@ -112,24 +114,97 @@ def symlink_unisolated_packages(env: DefaultIsolatedEnv) -> None: (env_site_packages / path.name).symlink_to(path) -def remove_avoided_requirements( - requires: set[str], avoided_requirements: set[str] | list[str] +def _remove_avoided_requirements( + requires: set[str], + avoided_requirements: set[str] | list[str], ) -> set[str]: + """ + Remove requirements that are in the list of avoided requirements. + + Parameters + ---------- + requires + The set of requirements to filter. + avoided_requirements + The set of requirements to avoid. + + Returns + ------- + The filtered set of requirements. + """ + avoided_requirements = set(avoided_requirements) for reqstr in list(requires): req = Requirement(reqstr) - for avoid_name in set(avoided_requirements): + for avoid_name in avoided_requirements: if avoid_name in req.name.lower(): requires.remove(reqstr) + break + return requires +def _replace_unisoloated_packages( + requires: set[str], + unisolated_packages: dict[str, str], +) -> tuple[set[str], set[str]]: + """ + Replace unisolated packages with the correct version. + + Parameters + ---------- + requires + The set of requirements to filter. + unisolated_packages + The dictionary of unisolated packages. + + Returns + ------- + tuple of (The filtered set of requirements, The set of unisolated requirements) + """ + requires_new = requires.copy() + unisolated = set() + for reqstr in list(requires): + req = Requirement(reqstr) + for name, version in unisolated_packages.items(): + if req.name == name and req.specifier.contains(version): + requires_new.remove(reqstr) + requires_new.add(f"{name}=={version}") + unisolated.add(name) + break + + + return requires_new, unisolated + + +def _install_cross_build_files(path: str, unisolated: set[str]) -> None: + """ + Install the cross build files to the isolated environment. + + Parameters + ---------- + path + The path to the isolated environment. + + unisolated + The set of unisolated packages. + """ + + sitepackagesdir = Path(_get_venv_paths(path)["purelib"]) + for name in unisolated: + base, files = get_unisolated_files(name) + for cross_build_file in files: + shutil.copy( + base / cross_build_file, + sitepackagesdir / cross_build_file, + ) + def install_reqs(env: DefaultIsolatedEnv, reqs: set[str]) -> None: - env.install( - remove_avoided_requirements( - reqs, - get_unisolated_packages() + AVOIDED_REQUIREMENTS, - ) - ) + reqs = _remove_avoided_requirements(reqs, AVOIDED_REQUIREMENTS) + reqs, unisolated = _replace_unisoloated_packages(reqs, get_unisolated_packages()) + + env.install(reqs) + + _install_cross_build_files(env.path, unisolated) def _build_in_isolated_env( diff --git a/pyodide_build/tests/test_xbuildenv.py b/pyodide_build/tests/test_xbuildenv.py index 40933d6e..76c37426 100644 --- a/pyodide_build/tests/test_xbuildenv.py +++ b/pyodide_build/tests/test_xbuildenv.py @@ -205,33 +205,6 @@ def test_install_force( assert (tmp_path / version / ".installed").exists() assert manager.current_version == version - def test_install_cross_build_packages( - self, tmp_path, dummy_xbuildenv_url, monkeypatch_subprocess_run_pip - ): - pip_called_with = monkeypatch_subprocess_run_pip - manager = CrossBuildEnvManager(tmp_path) - - download_path = tmp_path / "test" - manager._download(dummy_xbuildenv_url, download_path) - - xbuildenv_root = download_path / "xbuildenv" - xbuildenv_pyodide_root = xbuildenv_root / "pyodide-root" - manager._install_cross_build_packages(xbuildenv_root, xbuildenv_pyodide_root) - - assert len(pip_called_with) == 7 - assert pip_called_with[0:4] == ["pip", "install", "--no-user", "-t"] - assert pip_called_with[4].startswith( - str(xbuildenv_pyodide_root) - ) # hostsitepackages - assert pip_called_with[5:7] == ["-r", str(xbuildenv_root / "requirements.txt")] - - hostsitepackages = manager._host_site_packages_dir(xbuildenv_pyodide_root) - assert hostsitepackages.exists() - - cross_build_files = xbuildenv_root / "site-packages-extras" - for file in cross_build_files.iterdir(): - assert (hostsitepackages / file.name).exists() - def test_create_package_index(self, tmp_path, dummy_xbuildenv_url): manager = CrossBuildEnvManager(tmp_path) diff --git a/pyodide_build/vendor/_pypabuild.py b/pyodide_build/vendor/_pypabuild.py index 1683e252..c5772c40 100644 --- a/pyodide_build/vendor/_pypabuild.py +++ b/pyodide_build/vendor/_pypabuild.py @@ -24,6 +24,7 @@ import os import subprocess import sys +import sysconfig import traceback import warnings from collections.abc import Iterator @@ -124,3 +125,47 @@ def _handle_build_error() -> Iterator[None]: tb = traceback.format_exc(-1) # type: ignore[unreachable] _cprint("\n{dim}{}{reset}\n", tb.strip("\n")) _error(str(e)) + + + +def _get_venv_paths(path: str) -> dict[str, str]: + """ + Find the sysconfig paths for a virtual environment. + + Copied from pypabuild (https://github.com/pypa/build/blob/562907e605c3becb135ac52b6eb2aa939e84bdda/src/build/env.py#L326) + + Parameters + ---------- + path + The root path of the virtual environment + """ + config_vars = sysconfig.get_config_vars().copy() # globally cached, copy before altering it + config_vars['base'] = path + scheme_names = sysconfig.get_scheme_names() + if 'venv' in scheme_names: + # Python distributors with custom default installation scheme can set a + # scheme that can't be used to expand the paths in a venv. + # This can happen if build itself is not installed in a venv. + # The distributors are encouraged to set a "venv" scheme to be used for this. + # See https://bugs.python.org/issue45413 + # and https://github.com/pypa/virtualenv/issues/2208 + paths = sysconfig.get_paths(scheme='venv', vars=config_vars) + elif 'posix_local' in scheme_names: + # The Python that ships on Debian/Ubuntu varies the default scheme to + # install to /usr/local + # But it does not (yet) set the "venv" scheme. + # If we're the Debian "posix_local" scheme is available, but "venv" + # is not, we use "posix_prefix" instead which is venv-compatible there. + paths = sysconfig.get_paths(scheme='posix_prefix', vars=config_vars) + elif 'osx_framework_library' in scheme_names: + # The Python that ships with the macOS developer tools varies the + # default scheme depending on whether the ``sys.prefix`` is part of a framework. + # But it does not (yet) set the "venv" scheme. + # If the Apple-custom "osx_framework_library" scheme is available but "venv" + # is not, we use "posix_prefix" instead which is venv-compatible there. + paths = sysconfig.get_paths(scheme='posix_prefix', vars=config_vars) + else: + paths = sysconfig.get_paths(vars=config_vars) + + + return paths \ No newline at end of file diff --git a/pyodide_build/xbuildenv.py b/pyodide_build/xbuildenv.py index d9996c82..30f01bab 100644 --- a/pyodide_build/xbuildenv.py +++ b/pyodide_build/xbuildenv.py @@ -155,7 +155,7 @@ def install( as the current version of pyodide-build, make sure that the cross-build environment is compatible with the current version of Pyodide. skip_install_cross_build_packages - If True, skip installing the cross-build packages. This is mostly for testing purposes. + Deprecated, no longer used. force_install If True, force the installation even if the cross-build environment is not compatible @@ -204,11 +204,6 @@ def install( if not install_marker.exists(): logger.info("Installing Pyodide cross-build environment") - if not skip_install_cross_build_packages: - self._install_cross_build_packages( - xbuildenv_root, xbuildenv_pyodide_root - ) - if not url: # If installed from url, skip creating the PyPI index (version is not known) self._create_package_index(xbuildenv_pyodide_root, version) @@ -281,48 +276,6 @@ def _download(self, url: str, path: Path) -> None: warnings.simplefilter("ignore") shutil.unpack_archive(str(f_path), path) - def _install_cross_build_packages( - self, xbuildenv_root: Path, xbuildenv_pyodide_root: Path - ) -> None: - """ - Install package that are used in the cross-build environment. - - Parameters - ---------- - xbuildenv_root - Path to the xbuildenv directory. - xbuildenv_pyodide_root - Path to the pyodide-root directory inside the xbuildenv directory. - """ - host_site_packages = self._host_site_packages_dir(xbuildenv_pyodide_root) - host_site_packages.mkdir(exist_ok=True, parents=True) - result = subprocess.run( - [ - "pip", - "install", - "--no-user", - "-t", - str(host_site_packages), - "-r", - str(xbuildenv_root / "requirements.txt"), - ], - capture_output=True, - encoding="utf8", - ) - - if result.returncode != 0: - raise RuntimeError( - f"Failed to install cross-build packages: {result.stderr}" - ) - - # Copy the site-packages-extras (coming from the cross-build-files meta.yaml - # key) over the site-packages directory with the newly installed packages. - shutil.copytree( - xbuildenv_root / "site-packages-extras", - host_site_packages, - dirs_exist_ok=True, - ) - def _host_site_packages_dir( self, xbuildenv_pyodide_root: Path | None = None ) -> Path: From ee097077a8947f360f6e28f57a7f4b786f23686c Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Mon, 19 Aug 2024 12:09:09 +0000 Subject: [PATCH 02/71] Fix symlink --- pyodide_build/build_env.py | 2 +- pyodide_build/pypabuild.py | 15 ++++++++------- pyodide_build/tests/conftest.py | 2 +- pyodide_build/tests/test_build_env.py | 15 ++++++++++++++- pyodide_build/tests/test_pypabuild.py | 2 +- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py index 1d18474e..dfc01a18 100644 --- a/pyodide_build/build_env.py +++ b/pyodide_build/build_env.py @@ -221,7 +221,7 @@ def get_unisolated_files(package_name: str) -> tuple[Path, list[str]]: libdir = get_hostsitepackages() package_dir = libdir / package_name - return libdir, [str(f.relative_to(libdir)) for f in package_dir.rglob("*")] + return libdir, [str(f.relative_to(libdir)) for f in package_dir.rglob("*") if f.is_file()] diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index b84bf62b..f8c628b3 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -105,13 +105,6 @@ def symlink_unisolated_packages(env: DefaultIsolatedEnv) -> None: env_site_packages.mkdir(parents=True, exist_ok=True) shutil.copy(sysconfigdata_path, env_site_packages) - host_site_packages = Path(get_hostsitepackages()) - for name in get_unisolated_packages(): - for path in chain( - host_site_packages.glob(f"{name}*"), host_site_packages.glob(f"_{name}*") - ): - (env_site_packages / path.name).unlink(missing_ok=True) - (env_site_packages / path.name).symlink_to(path) def _remove_avoided_requirements( @@ -171,6 +164,14 @@ def _replace_unisoloated_packages( requires_new.add(f"{name}=={version}") unisolated.add(name) break + else: + # oldest-supported-numpy is a meta package for numpy + # TODO: use dependency resolution instead of hardcoding this + if req.name == "oldest-supported-numpy" and "numpy" in unisolated_packages: + requires_new.remove(reqstr) + requires_new.add(f"numpy=={unisolated_packages['numpy']}") + unisolated.add("numpy") + break return requires_new, unisolated diff --git a/pyodide_build/tests/conftest.py b/pyodide_build/tests/conftest.py index 2a504831..828561a5 100644 --- a/pyodide_build/tests/conftest.py +++ b/pyodide_build/tests/conftest.py @@ -97,7 +97,7 @@ def dummy_xbuildenv(dummy_xbuildenv_url, tmp_path, reset_env_vars, reset_cache): manager = CrossBuildEnvManager(tmp_path / xbuildenv_dirname()) manager.install( - version=None, url=dummy_xbuildenv_url, skip_install_cross_build_packages=True + version=None, url=dummy_xbuildenv_url, ) cur_dir = os.getcwd() diff --git a/pyodide_build/tests/test_build_env.py b/pyodide_build/tests/test_build_env.py index 9a2a1f12..f151cd32 100644 --- a/pyodide_build/tests/test_build_env.py +++ b/pyodide_build/tests/test_build_env.py @@ -66,7 +66,7 @@ def test_get_build_environment_vars( build_vars = build_env.get_build_environment_vars(manager.pyodide_root) # extra variables that does not come from config files. - extra_vars = set(["PYODIDE", "PYODIDE_PACKAGE_ABI", "PYTHONPATH"]) + extra_vars = set(["PYODIDE", "PYODIDE_PACKAGE_ABI"]) all_keys = set(BUILD_KEY_TO_VAR.values()) | extra_vars for var in build_vars: @@ -123,6 +123,19 @@ def test_get_build_environment_vars_host_env( e = build_env.get_build_environment_vars(pyodide_root) assert "HOME" not in e assert "RANDOM_ENV" not in e + + def test_get_unisolated_packages(self, dummy_xbuildenv, reset_env_vars, reset_cache): + expected = {"numpy", "scipy"} # this relies on the dummy xbuildenv file + pkgs = build_env.get_unisolated_packages() + for pkg in expected: + assert pkg in pkgs + + def test_get_unisolated_files(self, dummy_xbuildenv, reset_env_vars, reset_cache): + pkgs = build_env.get_unisolated_packages() + + for pkg in pkgs: + files = build_env.get_unisolated_files(pkg) + assert files def test_check_emscripten_version(dummy_xbuildenv, monkeypatch): diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py index 7a0af3fa..4f78d8c2 100644 --- a/pyodide_build/tests/test_pypabuild.py +++ b/pyodide_build/tests/test_pypabuild.py @@ -12,7 +12,7 @@ def install(self, reqs): def test_remove_avoided_requirements(): - assert pypabuild.remove_avoided_requirements( + assert pypabuild._remove_avoided_requirements( {"foo", "bar", "baz"}, {"foo", "bar", "qux"}, ) == {"baz"} From c806c0557703999253b310d556a1155f1247ce59 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Tue, 20 Aug 2024 10:53:20 +0000 Subject: [PATCH 03/71] type --- pyodide_build/build_env.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py index dfc01a18..bcb3372c 100644 --- a/pyodide_build/build_env.py +++ b/pyodide_build/build_env.py @@ -218,7 +218,7 @@ def get_unisolated_files(package_name: str) -> tuple[Path, list[str]]: if in_xbuildenv(): libdir = PYODIDE_ROOT / ".." / "site-packages-extras" else: - libdir = get_hostsitepackages() + libdir = Path(get_hostsitepackages()) package_dir = libdir / package_name return libdir, [str(f.relative_to(libdir)) for f in package_dir.rglob("*") if f.is_file()] From 033e552b6ab0569a08a72f7538c69185a0846bce Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:30:35 +0000 Subject: [PATCH 04/71] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyodide_build/build_env.py | 7 ++++--- pyodide_build/pypabuild.py | 14 ++++++-------- pyodide_build/tests/conftest.py | 3 ++- pyodide_build/tests/test_build_env.py | 6 ++++-- pyodide_build/vendor/_pypabuild.py | 22 +++++++++++----------- pyodide_build/xbuildenv.py | 1 - 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py index bcb3372c..715fbee8 100644 --- a/pyodide_build/build_env.py +++ b/pyodide_build/build_env.py @@ -219,10 +219,11 @@ def get_unisolated_files(package_name: str) -> tuple[Path, list[str]]: libdir = PYODIDE_ROOT / ".." / "site-packages-extras" else: libdir = Path(get_hostsitepackages()) - + package_dir = libdir / package_name - return libdir, [str(f.relative_to(libdir)) for f in package_dir.rglob("*") if f.is_file()] - + return libdir, [ + str(f.relative_to(libdir)) for f in package_dir.rglob("*") if f.is_file() + ] def platform() -> str: diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index f8c628b3..72c122f5 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -6,7 +6,6 @@ import traceback from collections.abc import Callable, Iterator, Mapping, Sequence from contextlib import contextmanager -from itertools import chain from pathlib import Path from tempfile import TemporaryDirectory from typing import Literal, cast @@ -18,10 +17,9 @@ from . import _f2c_fixes, common, pywasmcross from .build_env import ( get_build_flag, - get_hostsitepackages, get_pyversion, - get_unisolated_packages, get_unisolated_files, + get_unisolated_packages, platform, ) from .io import _BuildSpecExports @@ -29,9 +27,9 @@ _STYLES, _DefaultIsolatedEnv, _error, + _get_venv_paths, _handle_build_error, _ProjectBuilder, - _get_venv_paths, ) AVOIDED_REQUIREMENTS = [ @@ -120,7 +118,7 @@ def _remove_avoided_requirements( The set of requirements to filter. avoided_requirements The set of requirements to avoid. - + Returns ------- The filtered set of requirements. @@ -149,7 +147,7 @@ def _replace_unisoloated_packages( The set of requirements to filter. unisolated_packages The dictionary of unisolated packages. - + Returns ------- tuple of (The filtered set of requirements, The set of unisolated requirements) @@ -172,7 +170,6 @@ def _replace_unisoloated_packages( requires_new.add(f"numpy=={unisolated_packages['numpy']}") unisolated.add("numpy") break - return requires_new, unisolated @@ -185,7 +182,7 @@ def _install_cross_build_files(path: str, unisolated: set[str]) -> None: ---------- path The path to the isolated environment. - + unisolated The set of unisolated packages. """ @@ -199,6 +196,7 @@ def _install_cross_build_files(path: str, unisolated: set[str]) -> None: sitepackagesdir / cross_build_file, ) + def install_reqs(env: DefaultIsolatedEnv, reqs: set[str]) -> None: reqs = _remove_avoided_requirements(reqs, AVOIDED_REQUIREMENTS) reqs, unisolated = _replace_unisoloated_packages(reqs, get_unisolated_packages()) diff --git a/pyodide_build/tests/conftest.py b/pyodide_build/tests/conftest.py index 828561a5..176a08e1 100644 --- a/pyodide_build/tests/conftest.py +++ b/pyodide_build/tests/conftest.py @@ -97,7 +97,8 @@ def dummy_xbuildenv(dummy_xbuildenv_url, tmp_path, reset_env_vars, reset_cache): manager = CrossBuildEnvManager(tmp_path / xbuildenv_dirname()) manager.install( - version=None, url=dummy_xbuildenv_url, + version=None, + url=dummy_xbuildenv_url, ) cur_dir = os.getcwd() diff --git a/pyodide_build/tests/test_build_env.py b/pyodide_build/tests/test_build_env.py index f151cd32..2ccd8894 100644 --- a/pyodide_build/tests/test_build_env.py +++ b/pyodide_build/tests/test_build_env.py @@ -123,8 +123,10 @@ def test_get_build_environment_vars_host_env( e = build_env.get_build_environment_vars(pyodide_root) assert "HOME" not in e assert "RANDOM_ENV" not in e - - def test_get_unisolated_packages(self, dummy_xbuildenv, reset_env_vars, reset_cache): + + def test_get_unisolated_packages( + self, dummy_xbuildenv, reset_env_vars, reset_cache + ): expected = {"numpy", "scipy"} # this relies on the dummy xbuildenv file pkgs = build_env.get_unisolated_packages() for pkg in expected: diff --git a/pyodide_build/vendor/_pypabuild.py b/pyodide_build/vendor/_pypabuild.py index c5772c40..847c1542 100644 --- a/pyodide_build/vendor/_pypabuild.py +++ b/pyodide_build/vendor/_pypabuild.py @@ -127,7 +127,6 @@ def _handle_build_error() -> Iterator[None]: _error(str(e)) - def _get_venv_paths(path: str) -> dict[str, str]: """ Find the sysconfig paths for a virtual environment. @@ -139,33 +138,34 @@ def _get_venv_paths(path: str) -> dict[str, str]: path The root path of the virtual environment """ - config_vars = sysconfig.get_config_vars().copy() # globally cached, copy before altering it - config_vars['base'] = path + config_vars = ( + sysconfig.get_config_vars().copy() + ) # globally cached, copy before altering it + config_vars["base"] = path scheme_names = sysconfig.get_scheme_names() - if 'venv' in scheme_names: + if "venv" in scheme_names: # Python distributors with custom default installation scheme can set a # scheme that can't be used to expand the paths in a venv. # This can happen if build itself is not installed in a venv. # The distributors are encouraged to set a "venv" scheme to be used for this. # See https://bugs.python.org/issue45413 # and https://github.com/pypa/virtualenv/issues/2208 - paths = sysconfig.get_paths(scheme='venv', vars=config_vars) - elif 'posix_local' in scheme_names: + paths = sysconfig.get_paths(scheme="venv", vars=config_vars) + elif "posix_local" in scheme_names: # The Python that ships on Debian/Ubuntu varies the default scheme to # install to /usr/local # But it does not (yet) set the "venv" scheme. # If we're the Debian "posix_local" scheme is available, but "venv" # is not, we use "posix_prefix" instead which is venv-compatible there. - paths = sysconfig.get_paths(scheme='posix_prefix', vars=config_vars) - elif 'osx_framework_library' in scheme_names: + paths = sysconfig.get_paths(scheme="posix_prefix", vars=config_vars) + elif "osx_framework_library" in scheme_names: # The Python that ships with the macOS developer tools varies the # default scheme depending on whether the ``sys.prefix`` is part of a framework. # But it does not (yet) set the "venv" scheme. # If the Apple-custom "osx_framework_library" scheme is available but "venv" # is not, we use "posix_prefix" instead which is venv-compatible there. - paths = sysconfig.get_paths(scheme='posix_prefix', vars=config_vars) + paths = sysconfig.get_paths(scheme="posix_prefix", vars=config_vars) else: paths = sysconfig.get_paths(vars=config_vars) - - return paths \ No newline at end of file + return paths diff --git a/pyodide_build/xbuildenv.py b/pyodide_build/xbuildenv.py index 30f01bab..831441b8 100644 --- a/pyodide_build/xbuildenv.py +++ b/pyodide_build/xbuildenv.py @@ -1,6 +1,5 @@ import json import shutil -import subprocess import warnings from pathlib import Path from tempfile import NamedTemporaryFile From c8f4663c601dfe0ee7e57c55f4acc7a4e45f2a61 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Tue, 24 Sep 2024 12:49:58 +0000 Subject: [PATCH 05/71] cleanup [integration] --- pyodide_build/build_env.py | 18 ++++++++++-------- pyodide_build/pypabuild.py | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py index 19de8a24..7ffb4777 100644 --- a/pyodide_build/build_env.py +++ b/pyodide_build/build_env.py @@ -170,10 +170,12 @@ def get_hostsitepackages() -> str: @functools.cache def get_unisolated_packages() -> dict[str, str]: """ - Get a list of unisolated packages. - Unisolated packages are packages that are often used during the build process - and have some platform-specific files. When these packages are required during - the build process, we switch some files to platform-specific ones. + Get a map of unisolated packages. + + Unisolated packages are packages that are used during the build process + and have some platform-specific files. When these packages are used + during the build process, we switch need to switch platform-specific files, + in order to build the package correctly. Returns ------- @@ -182,14 +184,14 @@ def get_unisolated_packages() -> dict[str, str]: PYODIDE_ROOT = get_pyodide_root() + unisolated_packages = {} if in_xbuildenv(): - unisolated_file = PYODIDE_ROOT / ".." / "requirements.txt" - unisolated_packages = {} - for line in unisolated_file.read_text().splitlines(): + unisolated_packages_file = PYODIDE_ROOT / ".." / "requirements.txt" + + for line in unisolated_packages_file.read_text().splitlines(): name, version = line.split("==") unisolated_packages[name] = version else: - unisolated_packages = {} recipe_dir = PYODIDE_ROOT / "packages" recipes = load_all_recipes(recipe_dir) for name, config in recipes.items(): diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index 2bd4f05b..cdb6cf9a 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -136,7 +136,7 @@ def _remove_avoided_requirements( return requires -def _replace_unisoloated_packages( +def _replace_unisolated_packages( requires: set[str], unisolated_packages: dict[str, str], ) -> tuple[set[str], set[str]]: @@ -201,7 +201,7 @@ def _install_cross_build_files(path: str, unisolated: set[str]) -> None: def install_reqs(env: DefaultIsolatedEnv, reqs: set[str]) -> None: reqs = _remove_avoided_requirements(reqs, AVOIDED_REQUIREMENTS) - reqs, unisolated = _replace_unisoloated_packages(reqs, get_unisolated_packages()) + reqs, unisolated = _replace_unisolated_packages(reqs, get_unisolated_packages()) env.install(reqs) From 6521befb40d199d721bc00b30875f50bd8d31750 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:50:32 +0000 Subject: [PATCH 06/71] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyodide_build/build_env.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py index 212ca37d..e075f7ff 100644 --- a/pyodide_build/build_env.py +++ b/pyodide_build/build_env.py @@ -171,7 +171,7 @@ def get_hostsitepackages() -> str: def get_unisolated_packages() -> dict[str, str]: """ Get a map of unisolated packages. - + Unisolated packages are packages that are used during the build process and have some platform-specific files. When these packages are used during the build process, we switch need to switch platform-specific files, @@ -187,7 +187,7 @@ def get_unisolated_packages() -> dict[str, str]: unisolated_packages = {} if in_xbuildenv(): unisolated_packages_file = PYODIDE_ROOT / ".." / "requirements.txt" - + for line in unisolated_packages_file.read_text().splitlines(): name, version = line.split("==") unisolated_packages[name] = version From f0398160e59ae1706d991a0e5cc3eef9a6a7185b Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Tue, 15 Oct 2024 10:26:16 +0000 Subject: [PATCH 07/71] Add more test --- pyodide_build/pypabuild.py | 2 +- pyodide_build/tests/test_pypabuild.py | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index 61bf887b..b813a508 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -146,7 +146,7 @@ def _replace_unisolated_packages( requires The set of requirements to filter. unisolated_packages - The dictionary of unisolated packages. + The dictionary of unisolated packages [name: version]. Returns ------- diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py index 4f78d8c2..ef5b87ab 100644 --- a/pyodide_build/tests/test_pypabuild.py +++ b/pyodide_build/tests/test_pypabuild.py @@ -96,3 +96,30 @@ def test_get_build_env(tmp_path, dummy_xbuildenv): assert "ldflags" in wasmcross_args assert "exports" in wasmcross_args assert "builddir" in wasmcross_args + + +def test_replace_unisolated_packages(): + requires = {"foo", "bar<1.0", "baz==1.0", "qux"} + unisolated = { + "foo": "2.0", + "bar": "0.5", + "baz": "1.1", + } + + new_requires, replaced = pypabuild._replace_unisolated_packages(requires, unisolated) + assert new_requires == {"foo==2.0", "bar==0.5", "baz==1.0", "qux"} + assert replaced == {"foo", "bar"} + + +def test_replace_unisoloated_packages_oldest_supported_numpy(): + """ + oldest-supported-numpy is a special case where we want to replace it with numpy instead. + """ + requires = {"oldest-supported-numpy"} + unisolated = { + "numpy": "1.20", + } + + new_requires, replaced = pypabuild._replace_unisolated_packages(requires, unisolated) + assert new_requires == {"numpy==1.20"} + assert replaced == {"numpy"} \ No newline at end of file From 5b49ad5bd785f095879a7029bc86829f065c33e5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 10:26:34 +0000 Subject: [PATCH 08/71] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- pyodide_build/tests/test_pypabuild.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py index ef5b87ab..ffd677e3 100644 --- a/pyodide_build/tests/test_pypabuild.py +++ b/pyodide_build/tests/test_pypabuild.py @@ -106,7 +106,9 @@ def test_replace_unisolated_packages(): "baz": "1.1", } - new_requires, replaced = pypabuild._replace_unisolated_packages(requires, unisolated) + new_requires, replaced = pypabuild._replace_unisolated_packages( + requires, unisolated + ) assert new_requires == {"foo==2.0", "bar==0.5", "baz==1.0", "qux"} assert replaced == {"foo", "bar"} @@ -120,6 +122,8 @@ def test_replace_unisoloated_packages_oldest_supported_numpy(): "numpy": "1.20", } - new_requires, replaced = pypabuild._replace_unisolated_packages(requires, unisolated) + new_requires, replaced = pypabuild._replace_unisolated_packages( + requires, unisolated + ) assert new_requires == {"numpy==1.20"} - assert replaced == {"numpy"} \ No newline at end of file + assert replaced == {"numpy"} From 221f9ea9d77d7ea1d35e620143ba8969eef3b59d Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Tue, 15 Oct 2024 10:32:39 +0000 Subject: [PATCH 09/71] changelog --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ee49173..17c20d6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.30.0] - 2024/10/15 + +### Changed + +- Changed how build dependencies "numpy" and "scipy" is handled. + Previously, if a package depends on "numpy" or "scipy", the build system would + not install those packages. Instead, it pointed to the pre-built packages that pyodide-build provides. + This caused some issues when the package relies on some tools that are not available in the pre-built packages. + Now, the build system will install the "numpy" and "scipy" during the build process, but replace some of the + files with the pre-built ones to make sure the target platform is compatible to WebAssembly. + [#21](https://github.com/pyodide/pyodide-build/pull/21) + ## [0.29.0] - 2024/09/19 ### Added From 10edfb7813fd3b28fbbdcee722ed1682f2325b64 Mon Sep 17 00:00:00 2001 From: Gyeongjae Choi Date: Tue, 15 Oct 2024 11:53:35 +0000 Subject: [PATCH 10/71] More integration test files [integration] --- .../recipes/libf2c/extras/make.inc | 80 + integration_tests/recipes/libf2c/meta.yaml | 46 + .../libf2c/patches/0001-fix-arith.h.patch | 30 + .../patches/0002-fix-f2clibs-build.patch | 31 + .../0003-remove-redundant-symbols.patch | 34 + .../patches/0004-correct-return-types.patch | 81 + ...5-Remove-symbols-defined-in-OpenBLAS.patch | 27 + .../patches/0006-adjust-ld-ar-ranlib.patch | 33 + .../patches/0007-add-singlecomplex.patch | 10 + integration_tests/recipes/numpy/meta.yaml | 2 +- integration_tests/recipes/numpy/test_numpy.py | 364 + integration_tests/recipes/openblas/meta.yaml | 47 + .../0001-Add-Wno-return-type-flag.patch | 29 + ...ray-signature-with-scipy-expectation.patch | 25 + .../recipes/scipy/cmdline_test_file.py | 8 + integration_tests/recipes/scipy/info.md | 81 + integration_tests/recipes/scipy/meta.yaml | 182 + ...-Fix-dstevr-in-special-lapack_defs.h.patch | 32 + .../scipy/patches/0002-int-to-string.patch | 29 + .../scipy/patches/0003-gemm_-no-const.patch | 86 + .../patches/0004-make-int-return-values.patch | 345 + .../scipy/patches/0005-Fix-fitpack.patch | 112 + .../scipy/patches/0006-Fix-gees-calls.patch | 38 + ...-linalg-Remove-id_dist-Fortran-files.patch | 21867 ++++++++++++++++ ...0008-Mark-mvndst-functions-recursive.patch | 38 + .../patches/0009-Make-sreorth-recursive.patch | 111 + ...enblas-with-modules-that-require-f2c.patch | 76 + ...chec-inline-if-then-endif-constructs.patch | 94 + .../patches/0012-Remove-chla_transtype.patch | 27 + .../0013-Set-wrapper-return-type-to-int.patch | 25 + .../patches/0014-Skip-svd_gesdd-test.patch | 51 + .../patches/0015-Remove-f2py-generators.patch | 304 + ...-sf_error_state_lib-a-static-library.patch | 28 + ...move-test-modules-that-fail-to-build.patch | 74 + ...-Fix-lapack-larfg-function-signature.patch | 38 + .../recipes/scipy/scipy-conftest.py | 283 + .../recipes/scipy/scipy-pytest.js | 84 + integration_tests/recipes/scipy/test_scipy.py | 206 + 38 files changed, 25057 insertions(+), 1 deletion(-) create mode 100644 integration_tests/recipes/libf2c/extras/make.inc create mode 100644 integration_tests/recipes/libf2c/meta.yaml create mode 100644 integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch create mode 100644 integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch create mode 100644 integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch create mode 100644 integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch create mode 100644 integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch create mode 100644 integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch create mode 100644 integration_tests/recipes/libf2c/patches/0007-add-singlecomplex.patch create mode 100644 integration_tests/recipes/numpy/test_numpy.py create mode 100644 integration_tests/recipes/openblas/meta.yaml create mode 100644 integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch create mode 100644 integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch create mode 100644 integration_tests/recipes/scipy/cmdline_test_file.py create mode 100644 integration_tests/recipes/scipy/info.md create mode 100644 integration_tests/recipes/scipy/meta.yaml create mode 100644 integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch create mode 100644 integration_tests/recipes/scipy/patches/0002-int-to-string.patch create mode 100644 integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch create mode 100644 integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch create mode 100644 integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch create mode 100644 integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch create mode 100644 integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch create mode 100644 integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch create mode 100644 integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch create mode 100644 integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch create mode 100644 integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch create mode 100644 integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch create mode 100644 integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch create mode 100644 integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch create mode 100644 integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch create mode 100644 integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch create mode 100644 integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch create mode 100644 integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch create mode 100644 integration_tests/recipes/scipy/scipy-conftest.py create mode 100644 integration_tests/recipes/scipy/scipy-pytest.js create mode 100644 integration_tests/recipes/scipy/test_scipy.py diff --git a/integration_tests/recipes/libf2c/extras/make.inc b/integration_tests/recipes/libf2c/extras/make.inc new file mode 100644 index 00000000..7eaae7b5 --- /dev/null +++ b/integration_tests/recipes/libf2c/extras/make.inc @@ -0,0 +1,80 @@ +# -*- Makefile -*- +#################################################################### +# LAPACK make include file. # +# LAPACK, Version 3.2.1 # +# June 2009 # +#################################################################### +# +# See the INSTALL/ directory for more examples. +# +SHELL = /usr/bin/env sh +# +# The machine (platform) identifier to append to the library names +# +# WA for WebAssembly +PLAT = _WA +# +# Modify the FORTRAN and OPTS definitions to refer to the +# compiler and desired compiler options for your machine. NOOPT +# refers to the compiler options desired when NO OPTIMIZATION is +# selected. Define LOADER and LOADOPTS to refer to the loader +# and desired load options for your machine. +# +####################################################### +# This is used to compile C library +#CC = gcc # inherit $CC from emmake +# if no wrapping of the blas library is needed, uncomment next line +#CC = gcc -DNO_BLAS_WRAP +CFLAGS = -O3 -I$(TOPDIR)/INCLUDE -fPIC -DNO_BLAS_WRAP +LDFLAGS = -O3 +LOADER = $(CC) +LOADOPTS = +NOOPT = -O0 -I$(TOPDIR)/INCLUDE -fPIC +DRVCFLAGS = $(CFLAGS) +F2CCFLAGS = $(CFLAGS) +####################################################################### + +# +# Timer for the SECOND and DSECND routines +# +# Default : SECOND and DSECND will use a call to the EXTERNAL FUNCTION ETIME +# TIMER = EXT_ETIME +# For RS6K : SECOND and DSECND will use a call to the EXTERNAL FUNCTION ETIME_ +# TIMER = EXT_ETIME_ +# For gfortran compiler: SECOND and DSECND will use a call to the INTERNAL FUNCTION ETIME +# TIMER = INT_ETIME +# If your Fortran compiler does not provide etime (like Nag Fortran Compiler, etc...) +# SECOND and DSECND will use a call to the Fortran standard INTERNAL FUNCTION CPU_TIME +TIMER = INT_CPU_TIME +# If neither of this works...you can use the NONE value... In that case, SECOND and DSECND will always return 0 +# TIMER = NONE +# +# The archiver and the flag(s) to use when building archive (library) +# If you system has no ranlib, set RANLIB = echo. +# +ARCH = $(AR) +ARCHFLAGS= cr +#RANLIB = ranlib +# +# The location of BLAS library for linking the testing programs. +# The target's machine-specific, optimized BLAS library should be +# used whenever possible. +# +BLASLIB = ../../blas$(PLAT).a +# +# Location of the extended-precision BLAS (XBLAS) Fortran library +# used for building and testing extended-precision routines. The +# relevant routines will be compiled and XBLAS will be linked only if +# USEXBLAS is defined. +# +# USEXBLAS = Yes +XBLASLIB = +# XBLASLIB = -lxblas +# +# Names of generated libraries. +# +LAPACKLIB = lapack$(PLAT).a +F2CLIB = ../../F2CLIBS/libf2c.a +TMGLIB = tmglib$(PLAT).a +EIGSRCLIB = eigsrc$(PLAT).a +LINSRCLIB = linsrc$(PLAT).a diff --git a/integration_tests/recipes/libf2c/meta.yaml b/integration_tests/recipes/libf2c/meta.yaml new file mode 100644 index 00000000..45858b5a --- /dev/null +++ b/integration_tests/recipes/libf2c/meta.yaml @@ -0,0 +1,46 @@ +# We still download the full CLAPACK but we are only using the libf2c part of CLAPACK. +# libf2c part is needed for the f2ced Fortran files in scipy for example to +# define things like pow_dd, i_len, etc... +# +# Note f2clib package only creates f2clib.a, and f2clib.a symbols are added to +# libopenblas.so in the OpenBLAS meta.yaml. +package: + name: libf2c + version: CLAPACK-3.2.1 + tag: + - library +source: + sha256: 6dc4c382164beec8aaed8fd2acc36ad24232c406eda6db462bd4c41d5e455fac + url: http://www.netlib.org/clapack/clapack.tgz + extract_dir: CLAPACK-3.2.1 + patches: + - patches/0001-fix-arith.h.patch + - patches/0002-fix-f2clibs-build.patch + - patches/0003-remove-redundant-symbols.patch + - patches/0004-correct-return-types.patch + - patches/0005-Remove-symbols-defined-in-OpenBLAS.patch + # In CLAPACK's F2CLIBS/libf2c Makefile, some commands are mistakenly (?) hardcoded + # instead of using the right variables + - patches/0006-adjust-ld-ar-ranlib.patch + - patches/0007-add-singlecomplex.patch + + extras: + - [extras/make.inc, make.inc] + +build: + type: static_library + script: | + # The archive's contents have default permission 0750. If we use docker + # to build, then we will not own the contents in the host, which means + # we cannot navigate into the folder. Setting it to 0750 makes it + # easier to debug. + chmod -R o+rx . + + ARCH="emar" \ + emmake make -j ${PYODIDE_JOBS:-3} f2clib + mkdir -p ${WASM_LIBRARY_DIR}/{lib,include} + cp INCLUDE/f2c.h ${WASM_LIBRARY_DIR}/include + cp F2CLIBS/libf2c.a ${WASM_LIBRARY_DIR}/lib +about: + home: https://www.netlib.org/clapack/ + license: BSD-3-Clause diff --git a/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch b/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch new file mode 100644 index 00000000..7773825a --- /dev/null +++ b/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch @@ -0,0 +1,30 @@ +From 01990867ee7a641078505efba367a413a97f7802 Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Fri, 18 Mar 2022 19:59:25 -0700 +Subject: [PATCH 1/5] fix arith.h + +arith.h is a file generated at build time by compiling and running a C program. +Since we use emscripten to build throughout, the C program becomes a wasm file +and we call it differently. +--- + F2CLIBS/libf2c/Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/F2CLIBS/libf2c/Makefile b/F2CLIBS/libf2c/Makefile +index 0a3ed0d..a473ed8 100644 +--- a/F2CLIBS/libf2c/Makefile ++++ b/F2CLIBS/libf2c/Makefile +@@ -173,8 +173,8 @@ xwsne.o: fmt.h + arith.h: arithchk.c + $(CC) $(CFLAGS) -DNO_FPINIT arithchk.c -lm ||\ + $(CC) -DNO_LONG_LONG $(CFLAGS) -DNO_FPINIT arithchk.c -lm +- ./a.out >arith.h +- rm -f a.out arithchk.o ++ node a.out.js >arith.h ++ rm -f a.out.js a.out.wasm + + check: + xsum Notice README abort_.c arithchk.c backspac.c c_abs.c c_cos.c \ +-- +2.25.1 + diff --git a/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch b/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch new file mode 100644 index 00000000..89d94e5d --- /dev/null +++ b/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch @@ -0,0 +1,31 @@ +From d88133066f9f6312145c1186116fdb6446d3f7a5 Mon Sep 17 00:00:00 2001 +From: Michael Droettboom +Date: Fri, 18 Mar 2022 20:00:51 -0700 +Subject: [PATCH 2/5] fix f2clibs build + +emscripten produces LLVM bitcode here, not genuine object files, so it doesn't +make sense to strip symbols. + +(It would also fail because emcc uses the file extension to determine what kind +of object to output, and .xxx is not a recognized extension; this is the error +message you would receive if you try to run the commands) +--- + F2CLIBS/libf2c/Makefile | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/F2CLIBS/libf2c/Makefile b/F2CLIBS/libf2c/Makefile +index a473ed8..e51d826 100644 +--- a/F2CLIBS/libf2c/Makefile ++++ b/F2CLIBS/libf2c/Makefile +@@ -19,8 +19,6 @@ include ../../make.inc + # compile, then strip unnecessary symbols + .c.o: + $(CC) -c -DSkip_f2c_Undefs $(CFLAGS) $*.c +- ld -r -x -o $*.xxx $*.o +- mv $*.xxx $*.o + ## Under Solaris (and other systems that do not understand ld -x), + ## omit -x in the ld line above. + ## If your system does not have the ld command, comment out +-- +2.25.1 + diff --git a/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch b/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch new file mode 100644 index 00000000..bfd7257f --- /dev/null +++ b/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch @@ -0,0 +1,34 @@ +From 78ff0cec961d9eb4e94193995fe151e1ecdae9df Mon Sep 17 00:00:00 2001 +From: Roman Yurchak +Date: Fri, 18 Mar 2022 20:01:39 -0700 +Subject: [PATCH 3/5] remove redundant symbols + +Remove a few symbols from LAPACK that are redundantly defined with BLAS or are +ported in scipy. It wouldn't be an issue if we were linking dynamically, but +because of static linking otherwise we get errors at link time about symbols +defined twice. + + - Roman Yurchak (https://github.com/pyodide/pyodide/pull/238) +--- + SRC/Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/SRC/Makefile b/SRC/Makefile +index 5f1eb22..32e669b 100644 +--- a/SRC/Makefile ++++ b/SRC/Makefile +@@ -48,9 +48,9 @@ include ../make.inc + # + ####################################################################### + +-ALLAUX = maxloc.o ilaenv.o ieeeck.o lsamen.o xerbla.o xerbla_array.o iparmq.o \ ++ALLAUX = maxloc.o ilaenv.o ieeeck.o lsamen.o iparmq.o \ + ilaprec.o ilatrans.o ilauplo.o iladiag.o chla_transtype.o \ +- ../INSTALL/ilaver.o ../INSTALL/lsame.o ++ ../INSTALL/ilaver.o + + ALLXAUX = + +-- +2.25.1 + diff --git a/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch b/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch new file mode 100644 index 00000000..5d95f705 --- /dev/null +++ b/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch @@ -0,0 +1,81 @@ +From 572a3e20ba040b4f29bbef97a9db6658c10077d3 Mon Sep 17 00:00:00 2001 +From: Joe Marshall +Date: Fri, 18 Mar 2022 20:02:42 -0700 +Subject: [PATCH 4/5] correct return types + +Make return types to fortran subroutines consistently be int. Some functions are defined within clapack as variously +void and int return. Normal C compilers don't care, but emscripten is strict about return values. +--- + F2CLIBS/libf2c/ef1asc_.c | 2 +- + F2CLIBS/libf2c/f2ch.add | 4 ++-- + F2CLIBS/libf2c/s_cat.c | 6 +++--- + F2CLIBS/libf2c/s_copy.c | 4 ++-- + 4 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/F2CLIBS/libf2c/ef1asc_.c b/F2CLIBS/libf2c/ef1asc_.c +index 70be0bc..b2a82a2 100644 +--- a/F2CLIBS/libf2c/ef1asc_.c ++++ b/F2CLIBS/libf2c/ef1asc_.c +@@ -13,7 +13,7 @@ extern "C" { + extern VOID s_copy(); + ef1asc_(a, la, b, lb) ftnint *a, *b; ftnlen *la, *lb; + #else +-extern void s_copy(char*,char*,ftnlen,ftnlen); ++extern int s_copy(char*,char*,ftnlen,ftnlen); + int ef1asc_(ftnint *a, ftnlen *la, ftnint *b, ftnlen *lb) + #endif + { +diff --git a/F2CLIBS/libf2c/f2ch.add b/F2CLIBS/libf2c/f2ch.add +index a2acc17..f3f0466 100644 +--- a/F2CLIBS/libf2c/f2ch.add ++++ b/F2CLIBS/libf2c/f2ch.add +@@ -124,9 +124,9 @@ extern double r_sinh(float *); + extern double r_sqrt(float *); + extern double r_tan(float *); + extern double r_tanh(float *); +-extern void s_cat(char *, char **, integer *, integer *, ftnlen); ++extern int s_cat(char *, char **, integer *, integer *, ftnlen); + extern integer s_cmp(char *, char *, ftnlen, ftnlen); +-extern void s_copy(char *, char *, ftnlen, ftnlen); ++extern int s_copy(char *, char *, ftnlen, ftnlen); + extern int s_paus(char *, ftnlen); + extern integer s_rdfe(cilist *); + extern integer s_rdue(cilist *); +diff --git a/F2CLIBS/libf2c/s_cat.c b/F2CLIBS/libf2c/s_cat.c +index 8d92a63..54c4ff1 100644 +--- a/F2CLIBS/libf2c/s_cat.c ++++ b/F2CLIBS/libf2c/s_cat.c +@@ -28,11 +28,11 @@ extern + extern "C" { + #endif + +- VOID ++ + #ifdef KR_headers +-s_cat(lp, rpp, rnp, np, ll) char *lp, *rpp[]; ftnint rnp[], *np; ftnlen ll; ++int s_cat(lp, rpp, rnp, np, ll) char *lp, *rpp[]; ftnint rnp[], *np; ftnlen ll; + #else +-s_cat(char *lp, char *rpp[], ftnint rnp[], ftnint *np, ftnlen ll) ++int s_cat(char *lp, char *rpp[], ftnint rnp[], ftnint *np, ftnlen ll) + #endif + { + ftnlen i, nc; +diff --git a/F2CLIBS/libf2c/s_copy.c b/F2CLIBS/libf2c/s_copy.c +index 9dacfc7..8d8963f 100644 +--- a/F2CLIBS/libf2c/s_copy.c ++++ b/F2CLIBS/libf2c/s_copy.c +@@ -12,9 +12,9 @@ extern "C" { + /* assign strings: a = b */ + + #ifdef KR_headers +-VOID s_copy(a, b, la, lb) register char *a, *b; ftnlen la, lb; ++int s_copy(a, b, la, lb) register char *a, *b; ftnlen la, lb; + #else +-void s_copy(register char *a, register char *b, ftnlen la, ftnlen lb) ++int s_copy(register char *a, register char *b, ftnlen la, ftnlen lb) + #endif + { + register char *aend, *bend; +-- +2.25.1 + diff --git a/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch b/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch new file mode 100644 index 00000000..7dce211b --- /dev/null +++ b/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch @@ -0,0 +1,27 @@ +From eaf5c5db6e956036869255cb51831e720474d01d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= +Date: Fri, 7 Apr 2023 15:20:18 +0200 +Subject: [PATCH 5/5] Remove symbols defined in OpenBLAS + +--- + F2CLIBS/libf2c/Makefile | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/F2CLIBS/libf2c/Makefile b/F2CLIBS/libf2c/Makefile +index 57eff0d..136050f 100644 +--- a/F2CLIBS/libf2c/Makefile ++++ b/F2CLIBS/libf2c/Makefile +@@ -31,8 +31,8 @@ MISC = f77vers.o i77vers.o main.o s_rnge.o abort_.o exit_.o getarg_.o iargc_.o\ + getenv_.o signal_.o s_stop.o s_paus.o system_.o cabs.o ctype.o\ + derf_.o derfc_.o erf_.o erfc_.o sig_die.o uninit.o + POW = pow_ci.o pow_dd.o pow_di.o pow_hh.o pow_ii.o pow_ri.o pow_zi.o pow_zz.o +-CX = c_abs.o c_cos.o c_div.o c_exp.o c_log.o c_sin.o c_sqrt.o +-DCX = z_abs.o z_cos.o z_div.o z_exp.o z_log.o z_sin.o z_sqrt.o ++CX = c_cos.o c_div.o c_exp.o c_log.o c_sin.o c_sqrt.o ++DCX = z_cos.o z_div.o z_exp.o z_log.o z_sin.o z_sqrt.o + REAL = r_abs.o r_acos.o r_asin.o r_atan.o r_atn2.o r_cnjg.o r_cos.o\ + r_cosh.o r_dim.o r_exp.o r_imag.o r_int.o\ + r_lg10.o r_log.o r_mod.o r_nint.o r_sign.o\ +-- +2.34.1 + diff --git a/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch b/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch new file mode 100644 index 00000000..336f3761 --- /dev/null +++ b/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch @@ -0,0 +1,33 @@ +Index: CLAPACK-3.2.1/F2CLIBS/libf2c/Makefile +=================================================================== +--- CLAPACK-3.2.1.orig/F2CLIBS/libf2c/Makefile ++++ CLAPACK-3.2.1/F2CLIBS/libf2c/Makefile +@@ -70,8 +70,8 @@ OFILES = $(MISC) $(POW) $(CX) $(DCX) $(R + all: f2c.h signal1.h sysdep1.h libf2c.a clapack_install + + libf2c.a: $(OFILES) +- ar r libf2c.a $? +- -ranlib libf2c.a ++ $(ARCH) r libf2c.a $? ++ $(RANLIB) libf2c.a + + ## Shared-library variant: the following rule works on Linux + ## systems. Details are system-dependent. Under Linux, -fPIC +@@ -80,7 +80,7 @@ libf2c.a: $(OFILES) + ## of "cc -shared". + + libf2c.so: $(OFILES) +- cc -shared -o libf2c.so $(OFILES) ++ $(CC) -shared -o libf2c.so $(OFILES) + + ### If your system lacks ranlib, you don't need it; see README. + +@@ -117,7 +117,7 @@ sysdep1.h: sysdep1.h0 + + install: libf2c.a + cp libf2c.a $(LIBDIR) +- -ranlib $(LIBDIR)/libf2c.a ++ $(RANLIB) $(LIBDIR)/libf2c.a + + clapack_install: libf2c.a + mv libf2c.a .. diff --git a/integration_tests/recipes/libf2c/patches/0007-add-singlecomplex.patch b/integration_tests/recipes/libf2c/patches/0007-add-singlecomplex.patch new file mode 100644 index 00000000..982d3065 --- /dev/null +++ b/integration_tests/recipes/libf2c/patches/0007-add-singlecomplex.patch @@ -0,0 +1,10 @@ +--- a/INCLUDE/f2c.h ++++ b/INCLUDE/f2c.h +@@ -14,6 +14,7 @@ typedef short int shortint; + typedef float real; + typedef double doublereal; + typedef struct { real r, i; } complex; ++typedef struct { real r, i; } singlecomplex; + typedef struct { doublereal r, i; } doublecomplex; + typedef long int logical; + typedef short int shortlogical; diff --git a/integration_tests/recipes/numpy/meta.yaml b/integration_tests/recipes/numpy/meta.yaml index 9c3a8fee..3c1fdf81 100644 --- a/integration_tests/recipes/numpy/meta.yaml +++ b/integration_tests/recipes/numpy/meta.yaml @@ -30,4 +30,4 @@ about: home: https://www.numpy.org PyPI: https://pypi.org/project/numpy summary: NumPy is the fundamental package for array computing with Python. - license: BSD + license: BSD-3-Clause diff --git a/integration_tests/recipes/numpy/test_numpy.py b/integration_tests/recipes/numpy/test_numpy.py new file mode 100644 index 00000000..c446b936 --- /dev/null +++ b/integration_tests/recipes/numpy/test_numpy.py @@ -0,0 +1,364 @@ +import pytest +from pytest_pyodide import run_in_pyodide + + +def test_numpy(selenium): + selenium.load_package("numpy") + selenium.run( + """ + import numpy + x = numpy.ones((32, 64)) + """ + ) + selenium.run_js( + """ + let xpy = pyodide.runPython('x'); + self.x = xpy.toJs(); + xpy.destroy(); + """ + ) + assert selenium.run_js("return x.length === 32") + for i in range(32): + assert selenium.run_js(f"return x[{i}].length == 64") + for j in range(64): + assert selenium.run_js(f"return x[{i}][{j}] == 1") + + +def test_typed_arrays(selenium): + selenium.load_package("numpy") + selenium.run("import numpy") + for jstype, npytype in ( + ("Int8Array", "int8"), + ("Uint8Array", "uint8"), + ("Uint8ClampedArray", "uint8"), + ("Int16Array", "int16"), + ("Uint16Array", "uint16"), + ("Int32Array", "int32"), + ("Uint32Array", "uint32"), + ("Float32Array", "float32"), + ("Float64Array", "float64"), + ): + selenium.run_js(f"self.array = new {jstype}([1, 2, 3, 4]);\n") + assert selenium.run( + "from js import array\n" + "npyarray = numpy.asarray(array.to_py())\n" + f'npyarray.dtype.name == "{npytype}" ' + "and npyarray == [1, 2, 3, 4]" + ) + + +@pytest.mark.skip_pyproxy_check +@pytest.mark.parametrize("order", ("C", "F")) +@pytest.mark.parametrize( + "dtype", + ( + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "float32", + "float64", + ), +) +def test_python2js_numpy_dtype(selenium, order, dtype): + selenium.load_package("numpy") + selenium.run("import numpy as np") + + expected_result = [[[0, 1], [2, 3]], [[4, 5], [6, 7]]] + + def assert_equal(): + # We have to do this an element at a time, since the Selenium driver + # for Firefox does not convert TypedArrays to Python correctly + for i in range(2): + for j in range(2): + for k in range(2): + assert ( + selenium.run_js( + f"return Number(pyodide.globals.get('x').toJs()[{i}][{j}][{k}])" + ) + == expected_result[i][j][k] + ) + + selenium.run( + f""" + x = np.arange(8, dtype=np.{dtype}) + x = x.reshape((2, 2, 2)) + x = x.copy({order!r}) + """ + ) + assert_equal() + classname = selenium.run_js( + "return pyodide.globals.get('x').toJs()[0][0].constructor.name" + ) + # We expect a TypedArray subclass, such as Uint8Array, but not a plain-old + # Array + assert classname.endswith("Array") + assert classname != "Array" + selenium.run( + """ + x = x.byteswap().newbyteorder() + """ + ) + assert_equal() + classname = selenium.run_js( + "return pyodide.globals.get('x').toJs()[0][0].constructor.name" + ) + assert classname.endswith("Array") + assert classname != "Array" + + assert selenium.run("np.array([True, False])") == [True, False] + + +@pytest.mark.skip_pyproxy_check +def test_py2js_buffer_clear_error_flag(selenium): + selenium.load_package("numpy") + selenium.run("import numpy as np") + selenium.run("x = np.array([['string1', 'string2'], ['string3', 'string4']])") + selenium.run_js( + """ + pyodide.globals.get("x") + // Implicit assertion: this doesn't leave python error indicator set + // (automatically checked in conftest.py) + """ + ) + + +@pytest.mark.skip_pyproxy_check +@pytest.mark.parametrize( + "dtype", + ( + "int8", + "uint8", + "int16", + "uint16", + "int32", + "uint32", + "int64", + "uint64", + "float32", + "float64", + ), +) +def test_python2js_numpy_scalar(selenium, dtype): + selenium.load_package("numpy") + selenium.run("import numpy as np") + selenium.run( + f""" + x = np.{dtype}(1) + """ + ) + assert ( + selenium.run_js( + """ + return pyodide.globals.get('x') == 1 + """ + ) + is True + ) + selenium.run( + """ + x = x.byteswap().newbyteorder() + """ + ) + assert ( + selenium.run_js( + """ + return pyodide.globals.get('x') == 1 + """ + ) + is True + ) + + +@pytest.mark.skip_pyproxy_check +def test_runpythonasync_numpy(selenium_standalone): + selenium_standalone.run_async( + """ + import numpy as np + x = np.zeros(5) + """ + ) + for i in range(5): + assert selenium_standalone.run_js( + f"return pyodide.globals.get('x').toJs()[{i}] == 0" + ) + + +@pytest.mark.xfail_browsers( + firefox="Timeout in WebWorker when using numpy in Firefox 87" +) +@pytest.mark.driver_timeout(30) +def test_runwebworker_numpy(selenium_webworker_standalone): + output = selenium_webworker_standalone.run_webworker( + """ + import numpy as np + x = np.zeros(5) + str(x) + """ + ) + assert output == "[0. 0. 0. 0. 0.]" + + +@pytest.mark.skip_pyproxy_check +def test_get_buffer(selenium): + selenium.run_js( + """ + await pyodide.loadPackage(['numpy']); + pyodide.runPython(` + import numpy as np + x = np.arange(24) + z1 = x.reshape([8,3]) + z2 = z1[-1::-1] + z3 = z1[::,-1::-1] + z4 = z1[-1::-1,-1::-1] + `); + for(let x of ["z1", "z2", "z3", "z4"]){ + let z = pyodide.globals.get(x).getBuffer("u32"); + for(let idx1 = 0; idx1 < 8; idx1++) { + for(let idx2 = 0; idx2 < 3; idx2++){ + let v1 = z.data[z.offset + z.strides[0] * idx1 + z.strides[1] * idx2]; + let v2 = pyodide.runPython(`repr(${x}[${idx1}, ${idx2}])`); + console.log(`${v1}, ${typeof(v1)}, ${v2}, ${typeof(v2)}, ${v1===v2}`); + if(v1.toString() !== v2){ + throw new Error(`Discrepancy ${x}[${idx1}, ${idx2}]: ${v1} != ${v2}`); + } + } + } + z.release(); + } + """ + ) + + +@pytest.mark.skip_pyproxy_check +@pytest.mark.parametrize( + "arg", + [ + "np.arange(6).reshape((2, -1))", + "np.arange(12).reshape((3, -1))[::2, ::2]", + "np.arange(12).reshape((3, -1))[::-1, ::-1]", + "np.arange(12).reshape((3, -1))[::, ::-1]", + "np.arange(12).reshape((3, -1))[::-1, ::]", + "np.arange(12).reshape((3, -1))[::-2, ::-2]", + "np.arange(6).reshape((2, -1)).astype(np.int8, order='C')", + "np.arange(6).reshape((2, -1)).astype(np.int8, order='F')", + "np.arange(6).reshape((2, -1, 1))", + "np.ones((1, 1))[0:0]", # shape[0] == 0 + "np.ones(1)", # ndim == 0 + ] + + [ + f"np.arange(3).astype(np.{type_})" + for type_ in ["int8", "uint8", "int16", "int32", "float32", "float64"] + ], +) +def test_get_buffer_roundtrip(selenium, arg): + selenium.run_js( + f""" + await pyodide.loadPackage(['numpy']); + pyodide.runPython(` + import numpy as np + x = {arg} + `); + self.x_js_buf = pyodide.globals.get("x").getBuffer(); + x_js_buf.length = x_js_buf.data.length; + """ + ) + + selenium.run_js( + """ + pyodide.runPython(` + import itertools + from unittest import TestCase + from js import x_js_buf + assert_equal = TestCase().assertEqual + + assert_equal(x_js_buf.ndim, x.ndim) + assert_equal(x_js_buf.shape.to_py(), list(x.shape)) + assert_equal(x_js_buf.strides.to_py(), [s/x.itemsize for s in x.data.strides]) + assert_equal(x_js_buf.format, x.data.format) + if len(x) == 0: + assert x_js_buf.length == 0 + else: + minoffset = 1000 + maxoffset = 0 + for tup in itertools.product(*[range(n) for n in x.shape]): + offset = x_js_buf.offset + sum(x*y for (x,y) in zip(tup, x_js_buf.strides)) + minoffset = min(offset, minoffset) + maxoffset = max(offset, maxoffset) + assert_equal(x[tup], x_js_buf.data[offset]) + assert_equal(minoffset, 0) + assert_equal(maxoffset + 1, x_js_buf.length) + x_js_buf.release() + `); + """ + ) + + +def test_get_buffer_big_endian(selenium): + selenium.run_js( + """ + await pyodide.loadPackage(['numpy']); + self.a = pyodide.runPython(` + import numpy as np + np.arange(24, dtype="int16").byteswap().newbyteorder() + `); + """ + ) + with pytest.raises( + Exception, match="Javascript has no native support for big endian buffers" + ): + selenium.run_js("a.getBuffer()") + result = selenium.run_js( + """ + let buf = a.getBuffer("i8") + let result = Array.from(buf.data); + buf.release(); + a.destroy(); + return result; + """ + ) + assert len(result) == 48 + assert result[:18] == [0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8] + + +def test_get_buffer_error_messages(selenium): + with pytest.raises(Exception, match="Javascript has no Float16 support"): + selenium.run_js( + """ + await pyodide.loadPackage(['numpy']); + pyodide.runPython(` + import numpy as np + x = np.ones(2, dtype=np.float16) + `); + let x = pyodide.runPython("x"); + try { + x.getBuffer(); + } finally { + x.destroy(); + } + """ + ) + + +def test_fft(selenium): + selenium.run_js( + """ + await pyodide.loadPackage(['numpy']); + pyodide.runPython(` + import numpy + assert all(numpy.fft.fft([1, 1]) == [2, 0]) + `); + """ + ) + + +@run_in_pyodide(packages=["numpy"]) +def test_np_unique(selenium): + """Numpy comparator functions formerly had a fatal error, see PR #2110""" + import numpy as np + + np.unique(np.array([1.1, 1.1]), axis=-1) diff --git a/integration_tests/recipes/openblas/meta.yaml b/integration_tests/recipes/openblas/meta.yaml new file mode 100644 index 00000000..1325649a --- /dev/null +++ b/integration_tests/recipes/openblas/meta.yaml @@ -0,0 +1,47 @@ +package: + name: openblas + version: 0.3.26 + tag: + - library +source: + sha256: 4e6e4f5cb14c209262e33e6816d70221a2fe49eb69eaf0a06f065598ac602c68 + url: https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.26/OpenBLAS-0.3.26.tar.gz + patches: + - patches/0001-Add-Wno-return-type-flag.patch + - patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch + +build: + type: shared_library + script: | + # seems like .zip does not maintain executable flags, need to reset these + chmod u+x c_check + chmod u+x f_check + chmod u+x exports/gensymbol + # Replace void returns by int returns + sed -ri 's/void(\s+)BLASFUNC/int\1BLASFUNC/g' common_interface.h + sed -ri 's/void(\s+)cblas_/int\1cblas_/g' cblas.h ctest/*.c + sed -ri 's/void(\s+)(C?NAME)/int\1\2/g' interface/*.c + sed -ri 's/((extern)?.+) void ([a-z0-9]+_)/\1\2 int \3/g' lapack-netlib/SRC/*.c \ + lapack-netlib/SRC/DEPRECATED/*.c + # For some functions (mostly handling complex I think) f2c actually + # generate a function that returns void so I need to revert the void to int + # change the previous line does. + sed -ri 's@int ([cz](dotc|dotu|ladiv))@void \1@g' lapack-netlib/SRC/*.c\ + lapack-netlib/SRC/DEPRECATED/*.c + + emmake make libs shared CC=emcc HOSTCC=gcc TARGET=RISCV64_GENERIC NOFORTRAN=1 NO_LAPACKE=1 \ + USE_THREAD=0 LDFLAGS="${SIDE_MODULE_LDFLAGS}" + mkdir -p dist + # Add libf2c symbols to libopenblas.so + emcc ${WASM_LIBRARY_DIR}/lib/libf2c.a libopenblas.a ${SIDE_MODULE_LDFLAGS} \ + -o libopenblas.so + + cp libopenblas.so dist + emmake make install PREFIX=${WASM_LIBRARY_DIR} + +requirements: + host: + - libf2c +about: + home: https://www.openblas.net/ + license: BSD-3-Clause diff --git a/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch b/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch new file mode 100644 index 00000000..ae57a81a --- /dev/null +++ b/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch @@ -0,0 +1,29 @@ +From 09fd1aa0aa6a98e1cebaa6e34fca1e424dab8f48 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= +Date: Fri, 9 Dec 2022 16:40:13 +0100 +Subject: [PATCH 1/2] Add -Wno-return-type flag + +This is needed because we are changing many signatures to return int instead of +void with some regex expressions but we are not modifying the returned value + which would potentially be a lot more tricky. + +--- + Makefile.rule | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/Makefile.rule b/Makefile.rule +index 5f787a9c..6890046a 100644 +--- a/Makefile.rule ++++ b/Makefile.rule +@@ -228,7 +228,7 @@ NO_AFFINITY = 1 + # Common Optimization Flag; + # The default -O2 is enough. + # Flags for POWER8 are defined in Makefile.power. Don't modify COMMON_OPT +-# COMMON_OPT = -O2 ++COMMON_OPT = -O2 -Wno-return-type + + # gfortran option for LAPACK to improve thread-safety + # It is enabled by default in Makefile.system for gfortran +-- +2.34.1 + diff --git a/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch b/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch new file mode 100644 index 00000000..d7ba240d --- /dev/null +++ b/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch @@ -0,0 +1,25 @@ +From fb8f9ec54121a889783cce3d42ea841cc513a22e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= +Date: Fri, 7 Apr 2023 10:27:59 +0200 +Subject: [PATCH 2/2] Align xerbla_array signature with scipy expectation + +--- + lapack-netlib/SRC/xerbla_array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lapack-netlib/SRC/xerbla_array.c b/lapack-netlib/SRC/xerbla_array.c +index fe7d6d898..74d3ca96a 100644 +--- a/lapack-netlib/SRC/xerbla_array.c ++++ b/lapack-netlib/SRC/xerbla_array.c +@@ -600,7 +600,7 @@ array.f"> */ + + /* ===================================================================== */ + /* Subroutine */ void xerbla_array_(char *srname_array__, integer * +- srname_len__, integer *info, integer srname_array_len) ++ srname_len__, integer *info) + { + /* System generated locals */ + integer i__1, i__2, i__3; +-- +2.34.1 + diff --git a/integration_tests/recipes/scipy/cmdline_test_file.py b/integration_tests/recipes/scipy/cmdline_test_file.py new file mode 100644 index 00000000..0d98ef20 --- /dev/null +++ b/integration_tests/recipes/scipy/cmdline_test_file.py @@ -0,0 +1,8 @@ +import numpy as np +from scipy.sparse.linalg import svds + +rng = np.random.default_rng(0) +A = rng.random((10, 10)) + +res = svds(A, k=3, which="LM", random_state=0) +print("res", res) diff --git a/integration_tests/recipes/scipy/info.md b/integration_tests/recipes/scipy/info.md new file mode 100644 index 00000000..97efdd05 --- /dev/null +++ b/integration_tests/recipes/scipy/info.md @@ -0,0 +1,81 @@ +The biggest issue that comes up in building scipy is that we don't have a good +fortran to wasm compiler. Some version of flang classic might work. + +Instead of compiling from fortran directly, we rely on f2c to cross compile +the code to C and then compile C to wasm. We rely on f2c both directly and via +OpenBLAS which has f2c'd its Fortran files and then modified the generated C +files by hand. + +A big problem with f2c is that it cannot handle implicit casts of function +arguments, because it tries to guess the types of the arguments of the function +being called based on the types of the arguments at the call site. There are +two distinct versions of this: + +1. casts between number types -- we deal with this automatically in + `fix_inconsistent_decls` in `_f2c_fixes.py` +2. casts between char\* and int -- this is too annoying to deal with + automatically, so we write manual patches. + +Type 1: the fortran equivalent of the following C code: + +```C +double f(double x){ + return x + 5; +} + +double g(int x){ + return f(x); +} +``` + +gets f2c'd to + +```C +double f(double x){ + return x + 5; +} + +double g(int x){ + double f(int); + return f(x); +} +``` + +When we try to compile this, we get an error saying that f has been declared +with two different types. + +Type 2: For each string argument, the Fortran ABI adds arguments at the end of +the argument list. LAPACK never declares functions as taking strings, preferring +to call them integers: + +```C +int some_lapack_func(int *some_string, int *some_string_length){ + // ... +} +``` + +But then when we call it: `some_lapack_func("a string here", 14);` the f2c'd +version looks like: + +```C +int str_len = 14; +int some_lapack_func(int *some_string, int *some_string_length, fortranlen some_string_length_again); +some_lapack_func("a string here", &str_len, 14); +``` + +When changing `packages/scipy/meta.yaml`, rebuilding scipy takes time, it can +be convenient to only build a few sub-packages to reduce iteration time. You +can add something like this to `packages/scipy/meta.yaml`: + +```bash +# Define which sub-packages to keep +TO_KEEP='linalg|sparse|_lib|_build_utils' +# Update scipy/setup.py +perl -pi -e "s@(config.add_subpackage\(')(?!$TO_KEEP)@# \1\2@" scipy/setup.py +# delete unwanted folders to avoid unneeded cythonization +folders_to_delete=$(find scipy -mindepth 1 -maxdepth 1 -type d | grep -vP "$TO_KEEP") +rm -rf $folders_to_delete +``` + +Building only `scipy.(linalg|sparse|_lib|_build_utils)` takes ~4 minutes on my +machine compared to ~10-15 minutes for a full scipy build. diff --git a/integration_tests/recipes/scipy/meta.yaml b/integration_tests/recipes/scipy/meta.yaml new file mode 100644 index 00000000..959954fa --- /dev/null +++ b/integration_tests/recipes/scipy/meta.yaml @@ -0,0 +1,182 @@ +package: + name: scipy + version: 1.14.1 + tag: + - min-scipy-stack + top-level: + - scipy + +# See extra explanation in info.md +# +# For future reference: if you see the following errors: +# Declaration error: adjustable dimension on non-argument +# or: +# nonconstant array size +# you are trying to compile code that isn't written to the fortran 77 standard. +# The line number in the error points to the last line of the problematic +# subroutine. Try deleting it. + +source: + url: https://files.pythonhosted.org/packages/62/11/4d44a1f274e002784e4dbdb81e0ea96d2de2d1045b2132d5af62cc31fd28/scipy-1.14.1.tar.gz + sha256: 5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417 + + patches: + - patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch + - patches/0002-int-to-string.patch + - patches/0003-gemm_-no-const.patch + - patches/0004-make-int-return-values.patch + - patches/0005-Fix-fitpack.patch + - patches/0006-Fix-gees-calls.patch + - patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch + - patches/0008-Mark-mvndst-functions-recursive.patch + - patches/0009-Make-sreorth-recursive.patch + - patches/0010-Link-openblas-with-modules-that-require-f2c.patch + - patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch # remove with SciPy v1.15.0 + - patches/0012-Remove-chla_transtype.patch + - patches/0013-Set-wrapper-return-type-to-int.patch + - patches/0014-Skip-svd_gesdd-test.patch # remove with SciPy v1.15.0 + - patches/0015-Remove-f2py-generators.patch + - patches/0016-Make-sf_error_state_lib-a-static-library.patch + - patches/0017-Remove-test-modules-that-fail-to-build.patch + - patches/0018-Fix-lapack-larfg-function-signature.patch + +build: + cflags: | + -I$(WASM_LIBRARY_DIR)/include + -Wno-return-type + -DUNDERSCORE_G77 + -fvisibility=default + cxxflags: | + -fexceptions + -fvisibility=default + ldflags: | + -L$(NUMPY_LIB)/core/lib/ + -L$(NUMPY_LIB)/random/lib/ + -fexceptions + + # Exclude tests via Meson's install tags functionality. + unvendor-tests: true + # install-args=--tags=runtime,python-runtime,devel + # Disable when running tests, enable when a PR is ready, i.e., building for distribution. + backend-flags: | + build-dir=build + + # IMPORTANT: Other locations important in scipy build process: + # There are two files built in the "capture" pass that need patching: + # _blas_subroutines.h, and _cython + # Scipy has a bunch of custom logic implemented in + # pyodide-build/pyodide_build/_f2c_fixes.py. + script: | + set -x + git clone https://github.com/hoodmane/f2c.git --depth 1 + (cd f2c/src && cp makefile.u makefile && sed -i "s/gram.c:/gram.c1:/" makefile && make) + export F2C_PATH=$(pwd)/f2c/src/f2c + + echo F2C_PATH: $F2C_PATH + export NPY_BLAS_LIBS="-I$WASM_LIBRARY_DIR/include $WASM_LIBRARY_DIR/lib/libopenblas.so" + export NPY_LAPACK_LIBS="-I$WASM_LIBRARY_DIR/include $WASM_LIBRARY_DIR/lib/libopenblas.so" + + sed -i 's/void DQA/int DQA/g' scipy/integrate/__quadpack.h + + # Change many functions that return void into functions that return int + find scipy -name "*.c*" -type f | xargs sed -i 's/extern void F_FUNC/extern int F_FUNC/g' + + sed -i 's/void F_FUNC/int F_FUNC/g' scipy/odr/__odrpack.c + sed -i 's/^void/int/g' scipy/odr/odrpack.h + sed -i 's/^void/int/g' scipy/odr/__odrpack.c + + sed -i 's/void BLAS_FUNC/int BLAS_FUNC/g' scipy/special/lapack_defs.h + # sed -i 's/void F_FUNC/int F_FUNC/g' scipy/linalg/_lapack_subroutines.h + sed -i 's/extern void/extern int/g' scipy/optimize/__minpack.h + sed -i 's/void/int/g' scipy/linalg/cython_blas_signatures.txt + sed -i 's/void/int/g' scipy/linalg/cython_lapack_signatures.txt + sed -i 's/^void/int/g' scipy/interpolate/src/_fitpackmodule.c + + sed -i 's/extern void/extern int/g' scipy/sparse/linalg/_dsolve/SuperLU/SRC/*.{c,h} + sed -i 's/PUBLIC void/PUBLIC int/g' scipy/sparse/linalg/_dsolve/SuperLU/SRC/*.{c,h} + sed -i 's/^void/int/g' scipy/sparse/linalg/_dsolve/SuperLU/SRC/*.{c,h} + sed -i 's/^void/int/g' scipy/sparse/linalg/_dsolve/*.{c,h} + sed -i 's/void \(.\)print/int \1/g' scipy/sparse/linalg/_dsolve/SuperLU/SRC/*.{c,h} + sed -i 's/TYPE_GENERIC_FUNC(\(.*\), void)/TYPE_GENERIC_FUNC(\1, int)/g' scipy/sparse/linalg/_dsolve/_superluobject.h + + sed -i 's/^void/int/g' scipy/optimize/_trlib/trlib_private.h + sed -i 's/^void/int/g' scipy/optimize/_trlib/trlib/trlib_private.h + sed -i 's/^void/int/g' scipy/_build_utils/src/wrap_dummy_g77_abi.c + sed -i 's/, int)/)/g' scipy/optimize/_trlib/trlib_private.h + sed -i 's/, 1)/)/g' scipy/optimize/_trlib/trlib_private.h + + sed -i 's/^void/int/g' scipy/spatial/qhull_misc.h + sed -i 's/, size_t)/)/g' scipy/spatial/qhull_misc.h + sed -i 's/,1)/)/g' scipy/spatial/qhull_misc.h + + # Input error causes "duplicate symbol" linker errors. Empty out the file. + echo "" > scipy/sparse/linalg/_dsolve/SuperLU/SRC/input_error.c + + _retain-test-patterns: + - "*_page_trend_test.py" + - "*bws_test.py" + + cross-build-env: true + cross-build-files: + - scipy/linalg/cython_lapack.pxd + - scipy/linalg/cython_blas.pxd + +requirements: + host: + - numpy + - openblas + run: + - numpy + - openblas + executable: + - gfortran + +test: + imports: + - scipy + - scipy.cluster + - scipy.cluster.vq + - scipy.cluster.hierarchy + - scipy.constants + - scipy.fft + - scipy.fftpack + - scipy.integrate + - scipy.interpolate + - scipy.io + - scipy.io.arff + - scipy.io.matlab + - scipy.io.wavfile + - scipy.linalg + - scipy.linalg.blas + - scipy.linalg.cython_blas + - scipy.linalg.lapack + - scipy.linalg.cython_lapack + - scipy.linalg.interpolative + - scipy.misc + - scipy.ndimage + - scipy.odr + - scipy.optimize + - scipy.signal + - scipy.signal.windows + - scipy.sparse + - scipy.sparse.linalg + - scipy.sparse.csgraph + - scipy.spatial + - scipy.spatial.distance + - scipy.spatial.transform + - scipy.special + - scipy.stats + - scipy.stats.contingency + - scipy.stats.distributions + - scipy.stats.mstats + - scipy.stats.qmc +about: + home: https://www.scipy.org + PyPI: https://pypi.org/project/scipy + summary: "SciPy: Scientific Library for Python" + license: BSD-3-Clause +extra: + recipe-maintainers: + - lesteve + - steppi + - agriyakhetarpal diff --git a/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch b/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch new file mode 100644 index 00000000..ca6d80a0 --- /dev/null +++ b/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch @@ -0,0 +1,32 @@ +From 45a31145679c83f2719b6420f234d484b9459697 Mon Sep 17 00:00:00 2001 +From: Hood Chatham +Date: Fri, 18 Mar 2022 16:25:39 -0700 +Subject: [PATCH 1/18] Fix dstevr in special/lapack_defs.h + +--- + scipy/special/lapack_defs.h | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/scipy/special/lapack_defs.h b/scipy/special/lapack_defs.h +index 0d20ba1ca..d4325f71f 100644 +--- a/scipy/special/lapack_defs.h ++++ b/scipy/special/lapack_defs.h +@@ -8,13 +8,12 @@ extern void BLAS_FUNC(dstevr)(char *jobz, char *range, CBLAS_INT *n, double *d, + double *vl, double *vu, CBLAS_INT *il, CBLAS_INT *iu, double *abstol, + CBLAS_INT *m, double *w, double *z, CBLAS_INT *ldz, CBLAS_INT *isuppz, + double *work, CBLAS_INT *lwork, CBLAS_INT *iwork, CBLAS_INT *liwork, +- CBLAS_INT *info, size_t jobz_len, size_t range_len); ++ CBLAS_INT *info); + + static void c_dstevr(char *jobz, char *range, CBLAS_INT *n, double *d, double *e, + double *vl, double *vu, CBLAS_INT *il, CBLAS_INT *iu, double *abstol, + CBLAS_INT *m, double *w, double *z, CBLAS_INT *ldz, CBLAS_INT *isuppz, + double *work, CBLAS_INT *lwork, CBLAS_INT *iwork, CBLAS_INT *liwork, CBLAS_INT *info) { + BLAS_FUNC(dstevr)(jobz, range, n, d, e, vl, vu, il, iu, abstol, m, +- w, z, ldz, isuppz, work, lwork, iwork, liwork, info, +- 1, 1); ++ w, z, ldz, isuppz, work, lwork, iwork, liwork, info); + } +-- +2.34.1 + diff --git a/integration_tests/recipes/scipy/patches/0002-int-to-string.patch b/integration_tests/recipes/scipy/patches/0002-int-to-string.patch new file mode 100644 index 00000000..7a172cb2 --- /dev/null +++ b/integration_tests/recipes/scipy/patches/0002-int-to-string.patch @@ -0,0 +1,29 @@ +From d53ade3f03ba3557fd50fb38990d605f4ae7f8f1 Mon Sep 17 00:00:00 2001 +From: Hood Chatham +Date: Sat, 25 Dec 2021 18:04:18 -0800 +Subject: [PATCH 2/18] int to string + +f2c does not handle implicit casts of function arguments correctly. The msg +argument of `xerrwv` is defined to be an `int *`, and then implicitly cast +from a string at the call site. This doesn't work correctly. + +We redefine the type of the first argument to be string to fix the problem. +--- + scipy/integrate/odepack/xerrwv.f | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/scipy/integrate/odepack/xerrwv.f b/scipy/integrate/odepack/xerrwv.f +index 7e180e4f8..b940bb702 100644 +--- a/scipy/integrate/odepack/xerrwv.f ++++ b/scipy/integrate/odepack/xerrwv.f +@@ -1,5 +1,6 @@ + subroutine xerrwv (msg, nmes, nerr, level, ni, i1, i2, nr, r1, r2) +- integer msg, nmes, nerr, level, ni, i1, i2, nr, ++ character msg*1 ++ integer nmes, nerr, level, ni, i1, i2, nr, + 1 i, lun, lunit, mesflg, ncpw, nch, nwds + double precision r1, r2 + dimension msg(nmes) +-- +2.34.1 + diff --git a/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch b/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch new file mode 100644 index 00000000..3840f745 --- /dev/null +++ b/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch @@ -0,0 +1,86 @@ +From e528227dd37c8b0512381992c222789a114e3169 Mon Sep 17 00:00:00 2001 +From: Hood Chatham +Date: Sat, 18 Dec 2021 11:41:15 -0800 +Subject: [PATCH 3/18] gemm_ no const + +cgemm, dgemm, sgemm, and zgemm are declared with `const` in slu_cdefs.h, but +other places don't have the cosnt causing compile errors. +This patch drops the consts and fixes the problem. +--- + scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h | 6 +++--- + scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h | 6 +++--- + scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h | 6 +++--- + scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h | 6 +++--- + 4 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h +index dfc0516ac..92d7d7d6b 100644 +--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h ++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h +@@ -262,9 +262,9 @@ extern void ccheck_tempv(int, singlecomplex *); + + /*! \brief BLAS */ + +-extern int cgemm_(const char*, const char*, const int*, const int*, const int*, +- const singlecomplex*, const singlecomplex*, const int*, const singlecomplex*, +- const int*, const singlecomplex*, singlecomplex*, const int*); ++extern int cgemm_( char*, char*, int*, int*, int*, ++ singlecomplex*, singlecomplex*, int*, singlecomplex*, ++ int*, singlecomplex*, singlecomplex*, int*); + extern int ctrsv_(char*, char*, char*, int*, singlecomplex*, int*, + singlecomplex*, int*); + extern int ctrsm_(char*, char*, char*, char*, int*, int*, +diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h +index 3b5aa509f..1305641bd 100644 +--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h ++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h +@@ -260,9 +260,9 @@ extern void dcheck_tempv(int, double *); + + /*! \brief BLAS */ + +-extern int dgemm_(const char*, const char*, const int*, const int*, const int*, +- const double*, const double*, const int*, const double*, +- const int*, const double*, double*, const int*); ++extern int dgemm_( char*, char*, int*, int*, int*, ++ double*, double*, int*, double*, ++ int*, double*, double*, int*); + extern int dtrsv_(char*, char*, char*, int*, double*, int*, + double*, int*); + extern int dtrsm_(char*, char*, char*, char*, int*, int*, +diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h +index 9bb6a38e7..b013962a4 100644 +--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h ++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h +@@ -259,9 +259,9 @@ extern void scheck_tempv(int, float *); + + /*! \brief BLAS */ + +-extern int sgemm_(const char*, const char*, const int*, const int*, const int*, +- const float*, const float*, const int*, const float*, +- const int*, const float*, float*, const int*); ++extern int sgemm_( char*, char*, int*, int*, int*, ++ float*, float*, int*, float*, ++ int*, float*, float*, int*); + extern int strsv_(char*, char*, char*, int*, float*, int*, + float*, int*); + extern int strsm_(char*, char*, char*, char*, int*, int*, +diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h +index c6418d584..c5a2692be 100644 +--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h ++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h +@@ -262,9 +262,9 @@ extern void zcheck_tempv(int, doublecomplex *); + + /*! \brief BLAS */ + +-extern int zgemm_(const char*, const char*, const int*, const int*, const int*, +- const doublecomplex*, const doublecomplex*, const int*, const doublecomplex*, +- const int*, const doublecomplex*, doublecomplex*, const int*); ++extern int zgemm_( char*, char*, int*, int*, int*, ++ doublecomplex*, doublecomplex*, int*, doublecomplex*, ++ int*, doublecomplex*, doublecomplex*, int*); + extern int ztrsv_(char*, char*, char*, int*, doublecomplex*, int*, + doublecomplex*, int*); + extern int ztrsm_(char*, char*, char*, char*, int*, int*, +-- +2.34.1 + diff --git a/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch b/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch new file mode 100644 index 00000000..5abeb4f0 --- /dev/null +++ b/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch @@ -0,0 +1,345 @@ +From a86a2304fd925f815bbb0e0753e46a7b863e2de2 Mon Sep 17 00:00:00 2001 +From: Joe Marshall +Date: Wed, 6 Apr 2022 21:25:13 -0700 +Subject: [PATCH 4/18] make int return values + +The return values of f2c functions are insignificant in most cases, so often it +is treated as returning void, when it really should return int (values are +"returned" by writing to pointers passed as an argument, but an obscure feature +known as alternative returns can cause the return value to be significant). + +There's a big change to scipy/linalg/_cython_wrapper_generators.py, which is +called on build to generate python wrappers for lapack and BLAS. The change +makes everything call direct to CLAPACK with the correct function signatures +and also fixes some fortran -> c linking oddities that occur because f2py assumes +different function signatures to f2c, which in turn creates different function +signatures compared to what has been done in CLAPACK. + +f2py is patched in numpy to make subroutines return int. + +emscripten is very strict about void vs int returns and function signatures, so +we change everything to return int from subroutines, and signatures are altered +to be consistent. + +Co-Developed-by: Joe Marshall +Co-Authored-By: Joe Marshall +--- + scipy/_build_utils/src/wrap_g77_abi.c | 16 ++++++------ + scipy/integrate/_odepackmodule.c | 8 +++--- + scipy/odr/__odrpack.c | 2 +- + .../_dsolve/SuperLU/SRC/ilu_cdrop_row.c | 8 +++--- + .../_dsolve/SuperLU/SRC/ilu_scopy_to_ucol.c | 2 +- + .../_dsolve/SuperLU/SRC/scipy_slu_config.h | 3 +++ + .../linalg/_dsolve/SuperLU/SRC/sgssvx.c | 7 ++--- + .../linalg/_dsolve/SuperLU/SRC/slu_dcomplex.h | 5 +++- + .../linalg/_dsolve/SuperLU/SRC/slu_scomplex.h | 5 ++-- + scipy/sparse/linalg/_dsolve/_superlu_utils.c | 4 +-- + .../linalg/_eigen/arpack/ARPACK/SRC/debug.h | 20 +++++++------- + .../linalg/_eigen/arpack/ARPACK/SRC/stat.h | 26 +++++++++---------- + 12 files changed, 57 insertions(+), 49 deletions(-) + +diff --git a/scipy/_build_utils/src/wrap_g77_abi.c b/scipy/_build_utils/src/wrap_g77_abi.c +index f35c94f984..1872d335aa 100644 +--- a/scipy/_build_utils/src/wrap_g77_abi.c ++++ b/scipy/_build_utils/src/wrap_g77_abi.c +@@ -71,7 +71,7 @@ double_complex F_FUNC(wzdotu,WZDOTU)(CBLAS_INT *n, double_complex *zx, \ + return ret; + } + +-void BLAS_FUNC(sladiv)(float *xr, float *xi, float *yr, float *yi, \ ++int BLAS_FUNC(sladiv)(float *xr, float *xi, float *yr, float *yi, \ + float *retr, float *reti); + float_complex F_FUNC(wcladiv,WCLADIV)(float_complex *x, float_complex *y){ + float_complex ret; +@@ -83,7 +83,7 @@ float_complex F_FUNC(wcladiv,WCLADIV)(float_complex *x, float_complex *y){ + return ret; + } + +-void BLAS_FUNC(dladiv)(double *xr, double *xi, double *yr, double *yi, \ ++int BLAS_FUNC(dladiv)(double *xr, double *xi, double *yr, double *yi, \ + double *retr, double *reti); + double_complex F_FUNC(wzladiv,WZLADIV)(double_complex *x, double_complex *y){ + double_complex ret; +@@ -95,31 +95,31 @@ double_complex F_FUNC(wzladiv,WZLADIV)(double_complex *x, double_complex *y){ + return ret; + } + +-void F_FUNC(cdotcwrp,WCDOTCWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \ ++int F_FUNC(cdotcwrp,WCDOTCWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \ + CBLAS_INT *incx, float_complex *cy, CBLAS_INT *incy){ + *ret = F_FUNC(wcdotc,WCDOTC)(n, cx, incx, cy, incy); + } + +-void F_FUNC(zdotcwrp,WZDOTCWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \ ++int F_FUNC(zdotcwrp,WZDOTCWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \ + CBLAS_INT *incx, double_complex *zy, CBLAS_INT *incy){ + *ret = F_FUNC(wzdotc,WZDOTC)(n, zx, incx, zy, incy); + } + +-void F_FUNC(cdotuwrp,CDOTUWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \ ++int F_FUNC(cdotuwrp,CDOTUWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \ + CBLAS_INT *incx, float_complex *cy, CBLAS_INT *incy){ + *ret = F_FUNC(wcdotu,WCDOTU)(n, cx, incx, cy, incy); + } + +-void F_FUNC(zdotuwrp,ZDOTUWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \ ++int F_FUNC(zdotuwrp,ZDOTUWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \ + CBLAS_INT *incx, double_complex *zy, CBLAS_INT *incy){ + *ret = F_FUNC(wzdotu,WZDOTU)(n, zx, incx, zy, incy); + } + +-void F_FUNC(cladivwrp,CLADIVWRP)(float_complex *ret, float_complex *x, float_complex *y){ ++int F_FUNC(cladivwrp,CLADIVWRP)(float_complex *ret, float_complex *x, float_complex *y){ + *ret = F_FUNC(wcladiv,WCLADIV)(x, y); + } + +-void F_FUNC(zladivwrp,ZLADIVWRP)(double_complex *ret, double_complex *x, double_complex *y){ ++int F_FUNC(zladivwrp,ZLADIVWRP)(double_complex *ret, double_complex *x, double_complex *y){ + *ret = F_FUNC(wzladiv,WZLADIV)(x, y); + } + +diff --git a/scipy/integrate/_odepackmodule.c b/scipy/integrate/_odepackmodule.c +index 0c8067e652..d085939859 100644 +--- a/scipy/integrate/_odepackmodule.c ++++ b/scipy/integrate/_odepackmodule.c +@@ -156,17 +156,17 @@ static PyObject *odepack_error; + #endif + #endif + +-typedef void lsoda_f_t(F_INT *n, double *t, double *y, double *ydot); ++typedef int lsoda_f_t(F_INT *n, double *t, double *y, double *ydot); + typedef int lsoda_jac_t(F_INT *n, double *t, double *y, F_INT *ml, F_INT *mu, + double *pd, F_INT *nrowpd); + +-void LSODA(lsoda_f_t *f, F_INT *neq, double *y, double *t, double *tout, F_INT *itol, ++int LSODA(lsoda_f_t *f, F_INT *neq, double *y, double *t, double *tout, F_INT *itol, + double *rtol, double *atol, F_INT *itask, F_INT *istate, F_INT *iopt, + double *rwork, F_INT *lrw, F_INT *iwork, F_INT *liw, lsoda_jac_t *jac, + F_INT *jt); + + /* +-void ode_function(int *n, double *t, double *y, double *ydot) ++int ode_function(int *n, double *t, double *y, double *ydot) + { + ydot[0] = -0.04*y[0] + 1e4*y[1]*y[2]; + ydot[2] = 3e7*y[1]*y[1]; +@@ -175,7 +175,7 @@ void ode_function(int *n, double *t, double *y, double *ydot) + } + */ + +-void ++int + ode_function(F_INT *n, double *t, double *y, double *ydot) + { + /* +diff --git a/scipy/odr/__odrpack.c b/scipy/odr/__odrpack.c +index c806e33fbf..c4b822eb92 100644 +--- a/scipy/odr/__odrpack.c ++++ b/scipy/odr/__odrpack.c +@@ -13,7 +13,7 @@ + #include "odrpack.h" + + +-void F_FUNC(dodrc,DODRC)(void (*fcn)(F_INT *n, F_INT *m, F_INT *np, F_INT *nq, F_INT *ldn, F_INT *ldm, ++void F_FUNC(dodrc,DODRC)(int (*fcn)(F_INT *n, F_INT *m, F_INT *np, F_INT *nq, F_INT *ldn, F_INT *ldm, + F_INT *ldnp, double *beta, double *xplusd, F_INT *ifixb, F_INT *ifixx, + F_INT *ldifx, F_INT *ideval, double *f, double *fjacb, double *fjacd, + F_INT *istop), +diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_cdrop_row.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_cdrop_row.c +index c1dc7fcf8f..d1903db4a6 100644 +--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_cdrop_row.c ++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_cdrop_row.c +@@ -23,10 +23,10 @@ at the top-level directory. + #include + #include "slu_cdefs.h" + +-extern void cswap_(int *, singlecomplex [], int *, singlecomplex [], int *); +-extern void caxpy_(int *, singlecomplex *, singlecomplex [], int *, singlecomplex [], int *); +-extern void ccopy_(int *, singlecomplex [], int *, singlecomplex [], int *); +-extern void scopy_(int *, float [], int *, float [], int *); ++extern int cswap_(int *, singlecomplex [], int *, singlecomplex [], int *); ++extern int caxpy_(int *, singlecomplex *, singlecomplex [], int *, singlecomplex [], int *); ++extern int ccopy_(int *, singlecomplex [], int *, singlecomplex [], int *); ++extern int scopy_(int *, float [], int *, float [], int *); + extern float scasum_(int *, singlecomplex *, int *); + extern float scnrm2_(int *, singlecomplex *, int *); + extern double dnrm2_(int *, double [], int *); +diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_scopy_to_ucol.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_scopy_to_ucol.c +index 4e2654e8ac..d5b955d40e 100644 +--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_scopy_to_ucol.c ++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_scopy_to_ucol.c +@@ -26,7 +26,7 @@ at the top-level directory. + int num_drop_U; + #endif + +-extern void scopy_(int *, float [], int *, float [], int *); ++extern int scopy_(int *, float [], int *, float [], int *); + + #if 0 + static float *A; /* used in _compare_ only */ +diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h +index 5afc93b5d9..7ac5f80fb9 100644 +--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h ++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h +@@ -3,6 +3,9 @@ + + #include + ++#include "f2c.h" ++ ++ + /* + * Support routines + */ +diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgssvx.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgssvx.c +index 1395752d4c..7f5538140d 100644 +--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgssvx.c ++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgssvx.c +@@ -21,6 +21,8 @@ at the top-level directory. + */ + #include "slu_sdefs.h" + ++extern float slangs(char *, SuperMatrix *); ++ + /*! \brief + * + *
+@@ -377,8 +379,6 @@ sgssvx(superlu_options_t *options, SuperMatrix *A, int *perm_c, int *perm_r,
+     double    t0;      /* temporary time */
+     double    *utime;
+ 
+-    /* External functions */
+-    extern float slangs(char *, SuperMatrix *);
+ 
+     Bstore = B->Store;
+     Xstore = X->Store;
+@@ -573,7 +573,8 @@ printf("dgssvx: Fact=%4d, Trans=%4d, equed=%c\n",
+         } else {
+ 	    *(unsigned char *)norm = 'I';
+         }
+-        anorm = slangs(norm, AA);
++        anorm = slangs(norm, AA);    /* External functions */
++        extern float slangs(char *, SuperMatrix *);
+         sgscon(norm, L, U, anorm, rcond, stat, &info1);
+         utime[RCOND] = SuperLU_timer_() - t0;
+     }
+diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_dcomplex.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_dcomplex.h
+index 67e83bcc77..e5757d5c4d 100644
+--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_dcomplex.h
++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_dcomplex.h
+@@ -28,7 +28,10 @@ at the top-level directory.
+ #ifndef DCOMPLEX_INCLUDE
+ #define DCOMPLEX_INCLUDE
+ 
+-typedef struct { double r, i; } doublecomplex;
++#include"scipy_slu_config.h"
++
++// defined in clapack
++//typedef struct { double r, i; } doublecomplex;
+ 
+ 
+ /* Macro definitions */
+diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
+index 83be8c971f..047a07ce9c 100644
+--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
+@@ -27,8 +27,9 @@ at the top-level directory.
+ 
+ #ifndef SCOMPLEX_INCLUDE
+ #define SCOMPLEX_INCLUDE
+-
+-typedef struct { float r, i; } singlecomplex;
++#include"scipy_slu_config.h"
++// defined in  CLAPACK
++//typedef struct { float r, i; } singlecomplex;
+ 
+ 
+ /* Macro definitions */
+diff --git a/scipy/sparse/linalg/_dsolve/_superlu_utils.c b/scipy/sparse/linalg/_dsolve/_superlu_utils.c
+index 49b928a431..0822687719 100644
+--- a/scipy/sparse/linalg/_dsolve/_superlu_utils.c
++++ b/scipy/sparse/linalg/_dsolve/_superlu_utils.c
+@@ -243,12 +243,12 @@ int input_error(char *srname, int *info)
+  * Stubs for Harwell Subroutine Library functions that SuperLU tries to call.
+  */
+ 
+-void mc64id_(int *a)
++int mc64id_(int *a)
+ {
+     superlu_python_module_abort("chosen functionality not available");
+ }
+ 
+-void mc64ad_(int *a, int *b, int *c, int d[], int e[], double f[],
++int mc64ad_(int *a, int *b, int *c, int d[], int e[], double f[],
+ 	     int *g, int h[], int *i, int j[], int *k, double l[],
+ 	     int m[], int n[])
+ {
+diff --git a/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/debug.h b/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/debug.h
+index 5eb0bb1b3d..81a6efafb9 100644
+--- a/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/debug.h
++++ b/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/debug.h
+@@ -1,16 +1,16 @@
+-c
++
+ c\SCCS Information: @(#) 
+ c FILE: debug.h   SID: 2.3   DATE OF SID: 11/16/95   RELEASE: 2 
+ c
+ c     %---------------------------------%
+ c     | See debug.doc for documentation |
+ c     %---------------------------------%
+-      integer  logfil, ndigit, mgetv0,
+-     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
+-     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
+-     &         mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd
+-      common /debug/ 
+-     &         logfil, ndigit, mgetv0,
+-     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
+-     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
+-     &         mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd
++c      integer  logfil, ndigit, mgetv0,
++c     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
++c     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
++c     &         mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd
++c      common /debug/
++c     &         logfil, ndigit, mgetv0,
++c     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
++c     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
++c     &         mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd
+diff --git a/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h b/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h
+index 66a8e9f87f..81d49c3bd2 100644
+--- a/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h
++++ b/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h
+@@ -5,17 +5,17 @@ c
+ c\SCCS Information: @(#) 
+ c FILE: stat.h   SID: 2.2   DATE OF SID: 11/16/95   RELEASE: 2 
+ c
+-      real       t0, t1, t2, t3, t4, t5
+-      save       t0, t1, t2, t3, t4, t5
++c      real       t0, t1, t2, t3, t4, t5
++c      save       t0, t1, t2, t3, t4, t5
+ c
+-      integer    nopx, nbx, nrorth, nitref, nrstrt
+-      real       tsaupd, tsaup2, tsaitr, tseigt, tsgets, tsapps, tsconv,
+-     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
+-     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
+-     &           tmvopx, tmvbx, tgetv0, titref, trvec
+-      common /timing/ 
+-     &           nopx, nbx, nrorth, nitref, nrstrt,
+-     &           tsaupd, tsaup2, tsaitr, tseigt, tsgets, tsapps, tsconv,
+-     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
+-     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
+-     &           tmvopx, tmvbx, tgetv0, titref, trvec
++c      integer    nopx, nbx, nrorth, nitref, nrstrt
++c      real       tsaupd, tsaup2, tsaitr, tseigt, tsgets, tsapps, tsconv,
++c     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
++c     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
++c     &           tmvopx, tmvbx, tgetv0, titref, trvec
++c      common /timing/
++c     &           nopx, nbx, nrorth, nitref, nrstrt,
++c     &           tsaupd, tsaup2, tsaitr, tseigt, tsgets, tsapps, tsconv,
++c     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
++c     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
++c     &           tmvopx, tmvbx, tgetv0, titref, trvec
+-- 
+2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch b/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch
new file mode 100644
index 00000000..1df3145c
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch
@@ -0,0 +1,112 @@
+From c784d3a1ee38da88943364de4ea847a3b9cd155f Mon Sep 17 00:00:00 2001
+From: Hood Chatham 
+Date: Tue, 30 Aug 2022 11:51:53 -0700
+Subject: [PATCH 5/18] Fix fitpack
+
+---
+ scipy/interpolate/fitpack/dblint.f | 9 ++++-----
+ scipy/interpolate/fitpack/evapol.f | 5 ++---
+ scipy/interpolate/fitpack/fprati.f | 5 ++---
+ scipy/interpolate/fitpack/splint.f | 7 +++----
+ 4 files changed, 11 insertions(+), 15 deletions(-)
+
+diff --git a/scipy/interpolate/fitpack/dblint.f b/scipy/interpolate/fitpack/dblint.f
+index 8ae6b175f..51ec84744 100644
+--- a/scipy/interpolate/fitpack/dblint.f
++++ b/scipy/interpolate/fitpack/dblint.f
+@@ -1,7 +1,6 @@
+-      recursive function dblint(tx,nx,ty,ny,c,kx,ky,xb,xe,yb,
+-     *    ye,wrk) result(dblint_res)
++      recursive real*8 function dblint(tx,nx,ty,ny,c,kx,ky,xb,xe,yb,
++     *    ye,wrk)
+       implicit none
+-      real*8 :: dblint_res
+ c  function dblint calculates the double integral
+ c         / xe  / ye
+ c        |     |      s(x,y) dx dy
+@@ -75,7 +74,7 @@ c  we calculate the integrals of the normalized b-splines ni,kx+1(x)
+ c  we calculate the integrals of the normalized b-splines nj,ky+1(y)
+       call fpintb(ty,ny,wrk(nkx1+1),nky1,yb,ye)
+ c  calculate the integral of s(x,y)
+-      dblint_res = 0.
++      dblint = 0.
+       do 200 i=1,nkx1
+         res = wrk(i)
+         if(res.eq.0.) go to 200
+@@ -84,7 +83,7 @@ c  calculate the integral of s(x,y)
+         do 100 j=1,nky1
+           m = m+1
+           l = l+1
+-          dblint_res = dblint_res + res*wrk(l)*c(m)
++          dblint = dblint + res*wrk(l)*c(m)
+  100    continue
+  200  continue
+       return
+diff --git a/scipy/interpolate/fitpack/evapol.f b/scipy/interpolate/fitpack/evapol.f
+index f02569a40..1e4d65724 100644
+--- a/scipy/interpolate/fitpack/evapol.f
++++ b/scipy/interpolate/fitpack/evapol.f
+@@ -1,6 +1,5 @@
+-      recursive function evapol(tu,nu,tv,nv,c,rad,x,y) result(e_res)
++      recursive real*8 function evapol(tu,nu,tv,nv,c,rad,x,y)
+       implicit none
+-      real*8 :: e_res
+ c  function program evacir evaluates the function f(x,y) = s(u,v),
+ c  defined through the transformation
+ c      x = u*rad(v)*cos(v)    y = u*rad(v)*sin(v)
+@@ -78,7 +77,7 @@ c  calculate the (u,v)-coordinates of the given point.
+       if(u.gt.one) u = one
+ c  evaluate s(u,v)
+   10  call bispev(tu,nu,tv,nv,c,3,3,u,1,v,1,f,wrk,8,iwrk,2,ier)
+-      e_res = f
++      evapol = f
+       return
+       end
+ 
+diff --git a/scipy/interpolate/fitpack/fprati.f b/scipy/interpolate/fitpack/fprati.f
+index 71c57eb01..97b5851df 100644
+--- a/scipy/interpolate/fitpack/fprati.f
++++ b/scipy/interpolate/fitpack/fprati.f
+@@ -1,6 +1,5 @@
+-      recursive function fprati(p1,f1,p2,f2,p3,f3) result(fprati_res)
++      real*8 function fprati(p1,f1,p2,f2,p3,f3)
+       implicit none
+-      real*8 :: fprati_res
+ c  given three points (p1,f1),(p2,f2) and (p3,f3), function fprati
+ c  gives the value of p such that the rational interpolating function
+ c  of the form r(p) = (u*p+v)/(p+w) equals zero at p.
+@@ -26,6 +25,6 @@ c  adjust the value of p1,f1,p3 and f3 such that f1 > 0 and f3 < 0.
+       go to 40
+   30  p3 = p2
+       f3 = f2
+-  40  fprati_res = p
++  40  fprati = p
+       return
+       end
+diff --git a/scipy/interpolate/fitpack/splint.f b/scipy/interpolate/fitpack/splint.f
+index 02b00da6a..6024a0476 100644
+--- a/scipy/interpolate/fitpack/splint.f
++++ b/scipy/interpolate/fitpack/splint.f
+@@ -1,6 +1,5 @@
+-      recursive function splint(t,n,c,nc,k,a,b,wrk) result(splint_res)
++      real*8 function splint(t,n,c,nc,k,a,b,wrk)
+       implicit none
+-      real*8 :: splint_res
+ c  function splint calculates the integral of a spline function s(x)
+ c  of degree k, which is given in its normalized b-spline representation
+ c
+@@ -54,9 +53,9 @@ c  calculate the integrals wrk(i) of the normalized b-splines
+ c  ni,k+1(x), i=1,2,...nk1.
+       call fpintb(t,n,wrk,nk1,a,b)
+ c  calculate the integral of s(x).
+-      splint_res = 0.0d0
++      splint = 0.0d0
+       do 10 i=1,nk1
+-        splint_res = splint_res+c(i)*wrk(i)
++        splint = splint+c(i)*wrk(i)
+   10  continue
+       return
+       end
+-- 
+2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch b/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch
new file mode 100644
index 00000000..feabf913
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch
@@ -0,0 +1,38 @@
+From 8addc1da35bc63df651946ef14c723797a431e0c Mon Sep 17 00:00:00 2001
+From: Hood Chatham 
+Date: Mon, 26 Jun 2023 20:12:25 -0700
+Subject: [PATCH 6/18] Fix gees calls
+
+---
+ scipy/linalg/flapack_gen.pyf.src | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/scipy/linalg/flapack_gen.pyf.src b/scipy/linalg/flapack_gen.pyf.src
+index 04037fdca..3686cea86 100644
+--- a/scipy/linalg/flapack_gen.pyf.src
++++ b/scipy/linalg/flapack_gen.pyf.src
+@@ -1196,8 +1196,8 @@ subroutine gees(compute_v,sort_t,select,n,a,nrows,sdim,w,vs,
+     !  A = Z * T * Z^H  -- a complex matrix is in Schur form if it is upper
+     !  triangular
+ 
+-    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,w,vs,&ldvs,work,&lwork,rwork,bwork,&info,1,1)
+-    callprotoargument char*,char*,F_INT(*)(*),F_INT*,*,F_INT*,F_INT*,*,*,F_INT*,*,F_INT*,*,F_INT*,F_INT*,F_INT,F_INT
++    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,w,vs,&ldvs,work,&lwork,rwork,bwork,&info)
++    callprotoargument char*,char*,F_INT(*)(*),F_INT*,*,F_INT*,F_INT*,*,*,F_INT*,*,F_INT*,*,F_INT*,F_INT*
+ 
+     use gees__user__routines
+ 
+@@ -1226,8 +1226,8 @@ subroutine gees(compute_v,sort_t,select,n,a,nrows,sdim,wr,wi,v
+     !  A = Z * T * Z^H  -- a real matrix is in Schur form if it is upper quasi-
+     !  triangular with 1x1 and 2x2 blocks.
+ 
+-    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,wr,wi,vs,&ldvs,work,&lwork,bwork,&info,1,1)
+-    callprotoargument char*,char*,F_INT(*)(*,*),F_INT*,*,F_INT*,F_INT*,*,*,*,F_INT*,*,F_INT*,F_INT*,F_INT*,F_INT,F_INT
++    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,wr,wi,vs,&ldvs,work,&lwork,bwork,&info)
++    callprotoargument char*,char*,F_INT(*)(*,*),F_INT*,*,F_INT*,F_INT*,*,*,*,F_INT*,*,F_INT*,F_INT*,F_INT*
+ 
+     use gees__user__routines
+ 
+-- 
+2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch b/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
new file mode 100644
index 00000000..e3a57c5b
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
@@ -0,0 +1,21867 @@
+From 12ba8a395ce04194074a24d362143c22e7ac54bd Mon Sep 17 00:00:00 2001
+From: Ilhan Polat 
+Date: Tue, 23 Apr 2024 09:26:38 +0200
+Subject: [PATCH 7/18] MAINT:linalg:Remove id_dist Fortran files
+
+[skip ci]
+
+ENH:linalg:Translate id_dist F77 code to Cython
+
+MAINT:linalg: Convert double to numpy types
+
+MAINT:linalg: Fix linting and a typo in interpolative code
+
+DOC:linalg: Remove non-compliant dash character
+
+MAINT:linalg: Modify meson file for id_dist F77 translation
+
+[skip ci]
+
+MAINT:linalg: Adjust public api for the translated funcs
+
+[skip ci]
+
+ENH:linalg: Modify function signatures for interpolative
+
+[skip ci]
+
+TST:linalg: Adjust tests for the id_dist translation
+
+MAINT:linalg:Remove fortran wrappers for id_dist
+
+[skip ci]
+
+MAINT:linalg:Modify mypy.ini for interpolative Cython code
+
+DOC:linalg: Adjust interpolative docs due to new Cython code
+
+DOC:linalg: Fix grammar and typos
+---
+ mypy.ini                                      |    2 +-
+ scipy/linalg/_decomp_interpolative.pyx        | 1992 +++++++++++
+ scipy/linalg/_interpolative_backend.py        | 1681 ---------
+ scipy/linalg/interpolative.py                 |  316 +-
+ scipy/linalg/meson.build                      |   55 +-
+ scipy/linalg/src/id_dist/README.txt           |    6 -
+ scipy/linalg/src/id_dist/doc/doc.bib          |   19 -
+ scipy/linalg/src/id_dist/doc/doc.tex          |  977 ------
+ scipy/linalg/src/id_dist/doc/supertabular.sty |  483 ---
+ scipy/linalg/src/id_dist/src/dfft.f           | 3014 -----------------
+ scipy/linalg/src/id_dist/src/id_rand.f        |  379 ---
+ scipy/linalg/src/id_dist/src/id_rtrans.f      |  746 ----
+ scipy/linalg/src/id_dist/src/idd_frm.f        |  525 ---
+ scipy/linalg/src/id_dist/src/idd_house.f      |  288 --
+ scipy/linalg/src/id_dist/src/idd_id.f         |  560 ---
+ scipy/linalg/src/id_dist/src/idd_id2svd.f     |  384 ---
+ scipy/linalg/src/id_dist/src/idd_qrpiv.f      |  893 -----
+ scipy/linalg/src/id_dist/src/idd_sfft.f       |  443 ---
+ scipy/linalg/src/id_dist/src/idd_snorm.f      |  400 ---
+ scipy/linalg/src/id_dist/src/idd_svd.f        |  409 ---
+ scipy/linalg/src/id_dist/src/iddp_aid.f       |  386 ---
+ scipy/linalg/src/id_dist/src/iddp_asvd.f      |  180 -
+ scipy/linalg/src/id_dist/src/iddp_rid.f       |  376 --
+ scipy/linalg/src/id_dist/src/iddp_rsvd.f      |  216 --
+ scipy/linalg/src/id_dist/src/iddr_aid.f       |  208 --
+ scipy/linalg/src/id_dist/src/iddr_asvd.f      |  114 -
+ scipy/linalg/src/id_dist/src/iddr_rid.f       |  155 -
+ scipy/linalg/src/id_dist/src/iddr_rsvd.f      |  157 -
+ scipy/linalg/src/id_dist/src/idz_frm.f        |  419 ---
+ scipy/linalg/src/id_dist/src/idz_house.f      |  298 --
+ scipy/linalg/src/id_dist/src/idz_id.f         |  566 ----
+ scipy/linalg/src/id_dist/src/idz_id2svd.f     |  389 ---
+ scipy/linalg/src/id_dist/src/idz_qrpiv.f      |  898 -----
+ scipy/linalg/src/id_dist/src/idz_sfft.f       |  210 --
+ scipy/linalg/src/id_dist/src/idz_snorm.f      |  407 ---
+ scipy/linalg/src/id_dist/src/idz_svd.f        |  438 ---
+ scipy/linalg/src/id_dist/src/idzp_aid.f       |  390 ---
+ scipy/linalg/src/id_dist/src/idzp_asvd.f      |  207 --
+ scipy/linalg/src/id_dist/src/idzp_rid.f       |  379 ---
+ scipy/linalg/src/id_dist/src/idzp_rsvd.f      |  244 --
+ scipy/linalg/src/id_dist/src/idzr_aid.f       |  209 --
+ scipy/linalg/src/id_dist/src/idzr_asvd.f      |  118 -
+ scipy/linalg/src/id_dist/src/idzr_rid.f       |  156 -
+ scipy/linalg/src/id_dist/src/idzr_rsvd.f      |  159 -
+ scipy/linalg/src/id_dist/src/prini.f          |  113 -
+ scipy/linalg/tests/test_interpolative.py      |   78 +-
+ 46 files changed, 2159 insertions(+), 18883 deletions(-)
+ create mode 100644 scipy/linalg/_decomp_interpolative.pyx
+ delete mode 100644 scipy/linalg/_interpolative_backend.py
+ delete mode 100644 scipy/linalg/src/id_dist/README.txt
+ delete mode 100644 scipy/linalg/src/id_dist/doc/doc.bib
+ delete mode 100644 scipy/linalg/src/id_dist/doc/doc.tex
+ delete mode 100644 scipy/linalg/src/id_dist/doc/supertabular.sty
+ delete mode 100644 scipy/linalg/src/id_dist/src/dfft.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/id_rand.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/id_rtrans.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idd_frm.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idd_house.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idd_id.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idd_id2svd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idd_qrpiv.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idd_sfft.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idd_snorm.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idd_svd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/iddp_aid.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/iddp_asvd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/iddp_rid.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/iddp_rsvd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/iddr_aid.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/iddr_asvd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/iddr_rid.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/iddr_rsvd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idz_frm.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idz_house.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idz_id.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idz_id2svd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idz_qrpiv.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idz_sfft.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idz_snorm.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idz_svd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idzp_aid.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idzp_asvd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idzp_rid.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idzp_rsvd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idzr_aid.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idzr_asvd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idzr_rid.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/idzr_rsvd.f
+ delete mode 100644 scipy/linalg/src/id_dist/src/prini.f
+
+diff --git a/mypy.ini b/mypy.ini
+index 4417af39dc..4bdbdf9750 100644
+--- a/mypy.ini
++++ b/mypy.ini
+@@ -140,7 +140,7 @@ ignore_missing_imports = True
+ [mypy-scipy.linalg._solve_toeplitz]
+ ignore_missing_imports = True
+ 
+-[mypy-scipy.linalg._interpolative]
++[mypy-scipy.linalg._decomp_interpolative]
+ ignore_missing_imports = True
+ 
+ [mypy-scipy.optimize._group_columns]
+diff --git a/scipy/linalg/_decomp_interpolative.pyx b/scipy/linalg/_decomp_interpolative.pyx
+new file mode 100644
+index 000000000..e1a5b2a62
+--- /dev/null
++++ b/scipy/linalg/_decomp_interpolative.pyx
+@@ -0,0 +1,1992 @@
++# cython: boundscheck=False
++# cython: initializedcheck=False
++# cython: wraparound=False
++# cython: cdivision=True
++# cython: cpow=True
++
++"""
++This file is a Cython rewrite of the original Fortran code of "ID: A software package
++for low-rank approximation of matrices via interpolative decompositions, Version 0.4",
++written by Per-Gunnar Martinsson, Vladimir Rokhlin, Yoel Shkolnisky, and Mark Tygert.
++
++The original Fortran code can be found at the last author's current website
++http://tygert.com/software.html
++
++
++References
++----------
++
++N. Halko, P.G. Martinsson, and J. A. Tropp, "Finding structure with randomness:
++probabilistic algorithms for constructing approximate matrix decompositions",
++SIAM Review, 53 (2011), pp. 217-288. DOI:10.1137/090771806
++
++H. Cheng, Z. Gimbutas, P.G. Martinsson, V.Rokhlin, "On the Compression of Low
++Rank Matrices", SIAM Journal of Scientific Computing, 2005, Vol.26(4),
++DOI:10.1137/030602678
++
++
++
++Copyright (C) 2024 SciPy developers
++
++Redistribution and use in source and binary forms, with or without
++modification, are permitted provided that the following conditions are met:
++
++a. Redistributions of source code must retain the above copyright notice,
++   this list of conditions and the following disclaimer.
++b. Redistributions in binary form must reproduce the above copyright
++   notice, this list of conditions and the following disclaimer in the
++   documentation and/or other materials provided with the distribution.
++c. Names of the SciPy Developers may not be used to endorse or promote
++   products derived from this software without specific prior written
++   permission.
++
++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
++BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
++OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
++SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
++INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
++ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
++THE POSSIBILITY OF SUCH DAMAGE.
++
++
++Notes
++-----
++
++The translated functions from the original Fortran77 code are as follows (with various
++internal functions subsumed into respective functions):
++
++    idd_diffsnorm
++    idd_estrank
++    idd_findrank
++    idd_id2svd
++    idd_ldiv
++    idd_poweroftwo
++    idd_reconid
++    idd_snorm
++    iddp_aid
++    iddp_asvd
++    iddp_id
++    iddp_qrpiv
++    iddp_rid
++    iddp_rsvd
++    iddp_svd
++    iddr_aid
++    iddr_asvd
++    iddr_id
++    iddr_qrpiv
++    iddr_rid
++    iddr_rsvd
++    iddr_svd
++    idz_diffsnorm
++    idz_estrank
++    idz_findrank
++    idz_id2svd
++    idz_reconid
++    idz_snorm
++    idzp_aid
++    idzp_asvd
++    idzp_id
++    idzp_qrpiv
++    idzp_rid
++    idzp_rsvd
++    idzp_svd
++    idzr_aid
++    idzr_asvd
++    idzr_id
++    idzr_rid
++    idzr_rsvd
++    idzr_qrpiv
++    idzr_svd
++
++"""
++
++import numpy as np
++from numpy.typing import NDArray
++cimport numpy as cnp
++cnp.import_array()
++
++from cpython.mem cimport PyMem_Free, PyMem_Malloc, PyMem_Realloc
++from libc.math cimport hypot
++
++import scipy.linalg as la
++from scipy.fft import rfft, fft
++from scipy.sparse.linalg import LinearOperator
++
++from scipy.linalg.cython_lapack cimport dlarfgp, dorm2r, zunm2r, zlarfgp
++from scipy.linalg.cython_blas cimport dnrm2, dtrsm, dznrm2, ztrsm
++
++
++__all__ = ['idd_estrank', 'idd_ldiv', 'idd_poweroftwo', 'idd_reconid', 'iddp_aid',
++           'iddp_asvd', 'iddp_id', 'iddp_qrpiv', 'iddp_svd', 'iddr_aid', 'iddr_asvd',
++           'iddr_id', 'iddr_qrpiv', 'iddr_svd', 'idz_estrank', 'idz_reconid',
++           'idzp_aid', 'idzp_asvd', 'idzp_id', 'idzp_qrpiv', 'idzp_svd', 'idzr_aid',
++           'idzr_asvd', 'idzr_id', 'idzr_qrpiv', 'idzr_svd', 'idd_id2svd', 'idz_id2svd'
++           # LinearOperator funcs
++           'idd_findrank', 'iddp_rid', 'iddp_rsvd', 'iddr_rid', 'iddr_rsvd',
++           'idz_findrank', 'idzp_rid', 'idzp_rsvd', 'idzr_rid', 'idzr_rsvd',
++           'idd_snorm', 'idz_snorm', 'idd_diffsnorm', 'idz_diffsnorm'
++           ]
++
++
++def idd_diffsnorm(A: LinearOperator, B: LinearOperator, int its=20, rng=None):
++    cdef int n = A.shape[1], j = 0, intone = 1
++    cdef cnp.float64_t snorm = 0.0
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] v1
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] v2
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] u1
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] u2
++
++    if not rng:
++        rng = np.random.default_rng()
++    v1 = rng.uniform(low=-1., high=1., size=n)
++    v1 /= dnrm2(&n, &v1[0], &intone)
++
++    for j in range(its):
++        u1 = A.matvec(v1)
++        u2 = B.matvec(v1)
++        u1 -= u2
++        v1 = A.rmatvec(u1)
++        v2 = B.rmatvec(u1)
++        v1 -= v2
++
++        snorm = dnrm2(&n, &v1[0], &intone)
++        if snorm > 0.0:
++            v1 /= snorm
++
++        snorm = np.sqrt(snorm)
++
++    return snorm
++
++
++def idd_estrank(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a: NDArray, eps: float,
++                rng=None):
++    cdef int m = a.shape[0], n = a.shape[1]
++    cdef int intone = 1, n2, nsteps = 3, row, r, nstep, cols, k, nulls
++    cdef cnp.float64_t h, alpha, beta
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=3] albetas
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau_arr
++    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] subselect
++    cdef cnp.float64_t *aa
++    cdef cnp.float64_t *ff
++    cdef cnp.float64_t[:, ::1] Fmemview
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] giv2x2
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] rta
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] Fc
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] F
++
++    if not rng:
++        rng = np.random.default_rng()
++
++    n2 = idd_poweroftwo(m)
++
++    # This part is the initialization that is done via idd_frmi
++    # for a Subsampled Randomized Fourier Transfmrom (SRFT).
++
++    # Draw (nsteps x m x 2) arrays from [-1, 1) uniformly and scale
++    # each 2-element row to unity norm
++    albetas = rng.uniform(low=-1.0, high=1.0, size=[nsteps, m, 2])
++    aa = cnp.PyArray_DATA(albetas)
++    # Walk over every 2D row and normalize
++    for r in range(0, 2*nsteps*m, 2):
++        h = 1/hypot(aa[r], aa[r+1])
++        aa[r] *= h
++        aa[r+1] *= h
++
++    # idd_random_transf
++    rta = a.copy()
++
++    # Rotate and shuffle "a" nsteps-many times
++    giv2x2 = cnp.PyArray_ZEROS(2, [2, 2], cnp.NPY_FLOAT64, 0)
++    for nstep in range(nsteps):
++        for row in range(m-1):
++            alpha, beta = albetas[nstep, row, 0], albetas[nstep, row, 1]
++            giv2x2[0, 0] = alpha
++            giv2x2[0, 1] = beta
++            giv2x2[1, 0] = -beta
++            giv2x2[1, 1] = alpha
++            np.matmul(giv2x2, rta[row:row+2, :], out=rta[row:row+2, :])
++
++        rta = rta[rng.permutation(m), :]
++
++    # idd_subselect pick randomly n2-many rows
++    subselect = rng.choice(m, n2, replace=False)
++    rta = rta[subselect, :]
++
++    # Perform rfft on each column. Note that the first and the last
++    # element of the result is real valued (n2 is power of 2).
++    #
++    # We view the complex valued entries as two consecutive doubles
++    # (by also removing the 2nd and last all-0 rows -- see idd_frm).
++    # Then after transpose we do a final row shuffle after transpose.
++    Fc = rfft(rta.T, axis=1)
++    # Move the first col to second col
++    Fc[:, 0] *= 1.j
++    # Perform the final permutation
++    F = Fc.view(np.float64)[:, 1:-1].T[rng.permutation(n2), :]
++
++    Fcopy = F.copy()
++    cols = F.shape[1]
++    row = F.shape[0]
++    sssmax = 0.
++    ff = cnp.PyArray_DATA(F)
++    for r in range(cols):
++        h = dnrm2(&row, &ff[r], &cols)
++        if h > sssmax:
++            sssmax = h
++
++    tau_arr = cnp.PyArray_ZEROS(1, [cols], cnp.NPY_FLOAT64, 0)
++    k, nulls = 0, 0
++
++    # In Fortran id_dist, F is transposed and works on the columns
++    # Since we have a C-array we work directly on rows
++    # The reflectors are overwritten on rows of F directly
++    # Hence at any k'th step, we have
++    #
++    #            [ B  r  r  r  r  r  r  r ]
++    #            [           ....         ]
++    #            [           ....         ]
++    #            [ x  x  x  B  r  r  r  r ]
++    #            [ x  x  x  x  B  r  r  r ]
++    #            [ x  x  x  x  x  B  r  r ]
++    #            [ x  x  x  x  x  x  x  x ]
++    #            [ x  x  x  x  x  x  x  x ]
++    #
++
++    # Loop until nulls = 7, or krank+nulls = n2, or krank+nulls = n.
++    Fmemview = F
++    while (nulls < 7) and (k+nulls < min(n, n2)):
++        # Apply previous Householder reflectors
++        if k > 0:
++            for kk in range(k):
++                F[k, kk:] -= tau_arr[kk]*(F[kk, kk:] @ F[k, kk:])*F[kk, kk:]
++
++        # Get the next Householder reflector and store in F
++        r = cols-k
++        # n, alpha, x, incx, tau
++        dlarfgp(&r, &Fmemview[k, k], &Fmemview[k, k+1], &intone, &tau_arr[k])
++        beta = F[k, k]
++        F[k, k] = 1
++
++        if (beta <= eps*sssmax):
++            nulls += 1
++        k += 1
++
++    if nulls < 7:
++        k = 0
++
++    return k, Fcopy
++
++
++def idd_findrank(A: LinearOperator, cnp.float64_t eps, rng=None):
++    # Estimate the rank of A by repeatedly using A.rmatvec(random vec)
++
++    cdef int m = A.shape[0], n = A.shape[1], k = 0, kk = 0,r = n, krank
++    cdef int no_of_cols = 4, intone = 1, info = 0
++    cdef cnp.float64_t[::1] tau = cnp.PyArray_ZEROS(1, [min(m, n)], cnp.NPY_FLOAT64, 0)
++    cdef cnp.float64_t[::1] y = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] retarr
++
++    # The size of the QR decomposition is rank dependent which is unknown
++    # at runtime. Hence we don't want to allocate a dense version of the
++    # linear operator which can be too big. Instead, a typical "realloc double
++    # if run out of space" strategy is used here. Starts with 4*n
++    # Also, we hold the A.T @ x results in a separate array to return
++    # and do the same for that too.
++    cdef cnp.float64_t *ra = PyMem_Malloc(
++        sizeof(cnp.float64_t)*no_of_cols*n
++        )
++    cdef cnp.float64_t *reallocated_ra
++    cdef cnp.float64_t *ret = PyMem_Malloc(
++        sizeof(cnp.float64_t)*no_of_cols*n
++        )
++    cdef cnp.float64_t *reallocated_ret
++    cdef cnp.float64_t enorm = 0.0
++
++    if (not ra) or (not ret):
++        raise MemoryError("Failed to allocate at least required memory "
++                          f"{no_of_cols*n*8} bytes for"
++                          "'scipy.linalg.interpolative.idd_findrank()' "
++                          "function.")
++
++    if not rng:
++        rng = np.random.default_rng()
++
++    krank = 0
++    try:
++        while True:
++
++            # Generate random vector and rmatvec then save the result
++            x = rng.uniform(size=m)
++            y = A.rmatvec(x)
++            for kk in range(n):
++                ret[krank*n + kk] = y[kk]
++
++            if krank == 0:
++                enorm = dnrm2(&n, &y[0], &intone)
++            else:  # krank > 0
++                # Transpose-Apply previous Householder reflectors, if any
++                # SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, WORK, INFO
++                dorm2r('L','T', &n, &intone, &krank, &ra[0], &n,
++                       &tau[0], &y[0], &n, &ra[(no_of_cols-1)*n], &info)
++
++            # Get the next Householder reflector
++            r = n-krank
++            # N, ALPHA, X, INCX, TAU
++            dlarfgp(&r, &y[krank], &y[krank+1], &intone, &tau[krank])
++
++            for kk in range(n):
++                ra[krank*n + kk] = y[kk]
++
++            # Running out of space; try to double the size of ra
++            if krank == (no_of_cols-2):
++                reallocated_ra = PyMem_Realloc(
++                    ra, sizeof(cnp.float64_t)*no_of_cols*n*2)
++                reallocated_ret = PyMem_Realloc(
++                    ret, sizeof(cnp.float64_t)*no_of_cols*n*2)
++
++                if reallocated_ra and reallocated_ret:
++                    ra = reallocated_ra
++                    ret = reallocated_ret
++                    no_of_cols *= 2
++                else:
++                    raise MemoryError(
++                        "'scipy.linalg.interpolative.idd_findrank()' failed to "
++                        f"allocate the required memory,{no_of_cols*n*16} bytes "
++                        "while trying to determine the rank (currently "
++                        f"{krank}) of a LinearOperator with precision {eps}."
++                    )
++            krank += 1
++            if (y[krank-1] < eps*enorm) or (krank >= min(m, n)):
++                break
++    finally:
++        # Crashed or successfully ended up here
++        # Discard Householder vectors
++        PyMem_Free(ra)
++        retarr = cnp.PyArray_EMPTY(2, [krank, n], cnp.NPY_FLOAT64, 0)
++        for k in range(krank):
++            for kk in range(n):
++                retarr[k, kk] = ret[k*n+kk]
++        PyMem_Free(ret)
++
++    return krank, retarr
++
++
++def idd_id2svd(
++    cnp.ndarray[cnp.float64_t, mode='c', ndim=2] cols,
++    cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms,
++    cnp.ndarray[cnp.float64_t, ndim=2] proj,
++    ):
++    cdef int m = cols.shape[0], krank = cols.shape[1]
++    cdef int n = proj.shape[1] + krank, info, ci
++    cdef cnp.ndarray[cnp.float64_t, mode='fortran', ndim=2] C
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau1
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau2
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] UU
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
++    cdef cnp.ndarray[cnp.float64_t, ndim=2] V
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] VV
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] p
++
++    UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_FLOAT64, 0)
++    VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_FLOAT64, 0)
++    p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_FLOAT64, 0)
++
++    # idd_reconint
++    for ci in range(krank):
++        p[ci, perms[ci]] = 1.0
++
++    p[:, perms[krank:]] = proj[:, :]
++
++    inds1, tau1 = iddr_qrpiv(cols, krank)
++    # idd_rinqr and idd_rearr
++    r = np.triu(cols[:krank, :])
++    for ci in range(krank-1, -1, -1):
++        r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
++
++    t = p.T.copy()
++    inds2, tau2 = iddr_qrpiv(t, krank)
++    r2 = np.triu(t[:krank, :])
++    for ci in range(krank-1, -1, -1):
++        r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
++
++    r3 = r @ r2.T
++    UU[:krank, :krank], S, V = la.svd(r3,
++                                      full_matrices=False,
++                                      check_finite=False)
++
++    # Apply Q of col to U from the left, use cols as scratch
++    C = cols[:, :krank].copy(order='F')
++    dorm2r('R', 'T',
++           &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
++           &UU[0,0], &krank, &cols[0, 0], &info)
++
++    VV[:krank, :krank] = V[:, :].T
++    # Apply Q of t to V from the left
++    C = t[:, :krank].copy(order='F')
++    dorm2r('R', 'T',
++           &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
++           &VV[0, 0], &krank, &cols[0, 0], &info)
++
++    return UU, S, VV
++
++
++cdef inline int idd_ldiv(int l, int n) noexcept nogil:
++    cdef int m = l
++    while (n % m != 0):
++        m -= 1
++    return m
++
++
++cdef int idd_poweroftwo(int m) noexcept nogil:
++    """
++    Find the integer solution to l = floor(log2(m))
++    """
++    cdef int n = 1
++    while (n < m):
++        n <<= 1  # Times 2
++    return n >> 1  # Divide by 2
++
++
++def idd_reconid(B, idx, proj):
++    cdef int m = B.shape[0], krank = B.shape[1]
++    cdef int n = len(idx)
++    approx = np.zeros([m, n], dtype=np.float64)
++
++    approx[:, idx[:krank]] = B
++    approx[:, idx[krank:]] = B @ proj
++
++    return approx
++
++
++def idd_snorm(A: LinearOperator, int its=20, rng=None):
++    cdef int n = A.shape[1]
++    cdef int j = 0, intone = 1
++    cdef cnp.float64_t snorm = 0.0
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] v
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] u
++
++    if not rng:
++        rng = np.random.default_rng()
++    v = rng.uniform(low=-1., high=1., size=n)
++    v /= dnrm2(&n, &v[0], &intone)
++
++    for j in range(its):
++        u = A.matvec(v)
++        v = A.rmatvec(u)
++        snorm = dnrm2(&n, &v[0], &intone)
++        if snorm > 0.0:
++            v /= snorm
++
++        snorm = np.sqrt(snorm)
++
++    return snorm
++
++
++def iddp_aid(cnp.ndarray[cnp.float64_t, ndim=2] a: NDArray, eps: float, rng=None):
++    krank, proj = idd_estrank(a, eps, rng=rng)
++    if krank != 0:
++        proj = proj[:krank, :]
++        return iddp_id(proj, eps=eps)
++
++    return iddp_id(a, eps=eps)
++
++
++def iddp_asvd(cnp.ndarray[cnp.float64_t, ndim=2] a: NDArray, eps: float, rng=None):
++    cdef int m = a.shape[0], n = a.shape[1]
++    cdef int krank, info, ci
++    cdef cnp.ndarray[cnp.float64_t, mode='fortran', ndim=2] C
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau1
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau2
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] UU
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
++    cdef cnp.ndarray[cnp.float64_t, ndim=2] V
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] VV
++    cdef cnp.ndarray[cnp.float64_t, ndim=2] proj
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] perms
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] p
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] col
++
++    krank, perms, proj = iddp_aid(a.copy(), eps, rng=rng)
++
++    if krank > 0:
++        UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_FLOAT64, 0)
++        VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_FLOAT64, 0)
++
++        p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_FLOAT64, 0)
++        col = a[:, perms[:krank]].copy()
++
++        # idd_reconint
++        for ci in range(krank):
++            p[ci, perms[ci]] = 1.0
++
++        # p[np.arange(krank), perms[:krank]] = 1.
++        p[:, perms[krank:]] = proj[:, :]
++
++        inds1, tau1 = iddr_qrpiv(col, krank)
++        # idd_rinqr and idd_rearr
++        r = np.triu(col[:krank, :])
++        for ci in range(krank-1, -1, -1):
++            r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
++
++        t = p.T.copy()
++        inds2, tau2 = iddr_qrpiv(t, krank)
++        r2 = np.triu(t[:krank, :])
++        for ci in range(krank-1, -1, -1):
++            r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
++
++        r3 = r @ r2.T
++        UU[:krank, :krank], S, V = la.svd(r3, full_matrices=False)
++
++        # Apply Q of col to U from the left
++        C = col[:, :krank].copy(order='F')
++        dorm2r('R', 'T',
++               &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
++               &UU[0,0], &krank, &a[0, 0], &info)
++
++        VV[:krank, :krank] = V[:, :].T
++        # Apply Q of t to V from the left
++        C = t[:, :krank].copy(order='F')
++        dorm2r('R', 'T',
++               &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
++               &VV[0, 0], &krank, &a[0, 0], &info)
++
++    return UU, S, VV
++
++
++def iddp_id(cnp.ndarray[cnp.float64_t, ndim=2] a: NDArray, eps: float):
++    cdef int n = a.shape[1], krank, tmp_int, p
++    cdef cnp.float64_t one = 1
++    krank, _, inds = iddp_qrpiv(a, eps)
++
++    # Change pivots to permutation
++    perms = cnp.PyArray_ZEROS(1, [n], cnp.NPY_INT64, 0)
++    for p in range(n):
++        perms[p] = p
++
++    if krank > 0:
++        for p in range(krank):
++            # Apply pivots
++            tmp_int = perms[p]
++            perms[p] = perms[inds[p]]
++            perms[inds[p]] = tmp_int
++            # perms[[p, inds[p]]] = perms[[inds[p], p]]
++
++    # Let A = [A1, A2] and A1 has krank cols and upper triangular.
++    # Find X that satisfies A1 @ X = A2
++    # In SciPy.linalg this amounts to;
++    #
++    # proj = la.solve_triangular(a[:krank, :krank], a[:krank, krank:],
++    #                            lower=False, check_finite=False)
++    #
++    # Push into BLAS without transposes.
++    # A1 = a[:krank, :krank]
++    # A2 = a[:krank, krank:]
++    # Instead solve X @ A1.T = A2.T
++    # Fortran already sees A1 as A1.T and becomes lower tri, side = R
++
++    tmp_int = n - krank
++    # SIDE,UPLO,TRANSA,DIAG,M,N,ALPHA,A,LDA,B,LDB
++    dtrsm('R', 'L', 'N', 'N',
++          &tmp_int, &krank, &one, &a[0, 0], &n, &a[0, krank], &n)
++
++    return krank, np.array(perms), a[:krank, krank:]
++
++
++def iddp_qrpiv(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a, cnp.float64_t eps):
++    """
++    This is a minimal version of ?GEQP3 from LAPACK with an
++    additional early stopping criterion over given precision.
++
++    This function overwrites entries of "a" !
++    """
++
++    cdef int m = a.shape[0], n = a.shape[1]
++    cdef cnp.ndarray col_norms = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
++    cdef int k = 0, kpiv = 0, i = 0, tmp_int = 0, int_n = 0
++    cdef cnp.float64_t tmp_sca = 0.
++    cdef cnp.ndarray taus = cnp.PyArray_ZEROS(1, [m], cnp.NPY_FLOAT64, 0)
++    cdef cnp.ndarray ind = cnp.PyArray_ZEROS(1, [n], cnp.NPY_INT64, 0)
++    cdef cnp.float64_t[::1] taus_v = taus
++    cdef cnp.float64_t feps = 0.1e-16  # np.finfo(np.float64).eps
++    cdef cnp.float64_t ssmax, ssmaxin
++    cdef int nupdate = 0
++
++    for i in range(n):
++        col_norms[i] = dnrm2(&m, &a[0, i], &n)**2
++
++    kpiv = np.argmax(col_norms)
++    ssmax = col_norms[kpiv]
++    ssmaxin = ssmax
++
++    for k in range(min(m, n)):
++
++        # Pivoting
++        ind[k] = kpiv
++        # Swap columns a[:, k] and a[:, kpiv]
++        a[:, [kpiv, k]] = a[:, [k, kpiv]]
++
++        # Swap col_norms[krank] and col_norms[kpiv]
++        col_norms[[kpiv, k]] = col_norms[[k, kpiv]]
++
++        if k < m-1:
++            # Compute the householder reflector for column k
++            tmp_sca = a[k, k]
++            # FIX: Convert these to F_INT
++            tmp_int = (m - k)
++            int_n = n
++            dlarfgp(&tmp_int, &tmp_sca, &a[k+1, k], &int_n, &taus_v[k])
++
++            # Overwrite with 1. for easy matmul
++            a[k, k] = 1
++            if k < n-1:
++                # Apply the householder reflector to the rest on the right
++                a[k:, k+1:] -= np.outer(taus[k]*a[k:, k], a[k:, k] @ a[k:, k+1:])
++
++            # Put back the beta in place
++            a[k, k] = tmp_sca
++
++            # Update the norms
++            col_norms[k] = 0
++            col_norms[k+1:] -= a[k, k+1:]**2
++            ssmax = 0
++            kpiv = k+1
++            if k < n-1:
++                kpiv = np.argmax(col_norms[k+1:]) + (k + 1)
++                ssmax = col_norms[kpiv]
++
++            if (((ssmax < 1000*feps*ssmaxin) and (nupdate == 0)) or
++                    ((ssmax < ((1000*feps)**2)*ssmaxin) and (nupdate == 1))):
++                nupdate += 1
++                ssmax = 0
++                kpiv = k+1
++
++                if k < n-1:
++                    for i in range(k+1, n):
++                        tmp_int = m-k-1
++                        col_norms[i] = dnrm2(&tmp_int, &a[k+1, i], &n)**2
++                    kpiv = np.argmax(col_norms[k+1:]) + (k + 1)
++                    ssmax = col_norms[kpiv]
++        if (ssmax <= (eps**2)*ssmaxin):
++            break
++    # a is overwritten; return numerical rank and pivots
++    return k + 1, taus, ind
++
++
++def iddp_rid(A: LinearOperator, cnp.float64_t eps, rng=None):
++    _, ret = idd_findrank(A, eps, rng)
++    return iddp_id(ret, eps)
++
++
++def iddp_rsvd(A: LinearOperator, cnp.float64_t eps, rng=None):
++    cdef int n = A.shape[1]
++    cdef int krank, j
++    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms
++    cdef cnp.ndarray[cnp.float64_t, ndim=2] proj
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] col
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] x
++
++    krank, perms, proj = iddp_rid(A, eps, rng)
++    if krank > 0:
++        # idd_getcols
++        col = cnp.PyArray_EMPTY(2, [n, krank], cnp.NPY_FLOAT64, 0)
++        x = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
++
++        for j in range(krank):
++            x[perms[j]] = 1.
++            col[:, j] = A.matvec(x)
++            x[perms[j]] = 0.
++
++        return idd_id2svd(cols=col, perms=perms, proj=proj)
++
++    # TODO: figure out empty return
++    return None
++
++
++def iddp_svd(cnp.ndarray[cnp.float64_t, ndim=2] a: NDArray, eps: float):
++    """a is overwritten"""
++    cdef int m = a.shape[0], krank, info
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] taus
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] UU
++    cdef cnp.ndarray[cnp.float64_t, mode='fortran', ndim=2] C
++
++    # Get the pivoted QR
++    krank, taus, inds = iddp_qrpiv(a, eps)
++
++    if krank > 0:
++        r = np.triu(a[:krank, :])
++        # Apply pivots in reverse
++        for p in range(krank-1, -1, -1):
++            r[:, [p, inds[p]]] = r[:, [inds[p], p]]
++
++        # JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO
++        # dgesvd('S', 'O', &krank, &n)
++        U, S, V = la.svd(r, full_matrices=False)
++
++        # Apply Q to U via dorm2r
++        # Possibly U is shorter than Q
++        UU = np.zeros([m, krank], dtype=a.dtype)
++        UU[:krank, :krank] = U
++        # Do the transpose dance for C-layout, use a for scratch
++        C = a[:, :krank].copy(order='F')
++        dorm2r('R', 'T',
++               &krank, &m, &krank, &C[0, 0], &m, &taus[0],
++               &UU[0,0], &krank, &a[0, 0], &info)
++
++    return UU, S, V
++
++
++def iddr_aid(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a: NDArray, int krank,
++             rng=None):
++    cdef int m = a.shape[0], n = a.shape[1], n2, nsteps = 3, row, r, nstep, L
++    cdef cnp.float64_t h, alpha, beta
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=3] albetas
++    cdef cnp.ndarray[cnp.npy_int64, mode='c', ndim=1] subselect
++    cdef cnp.float64_t *aa
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] giv2x2
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] rta
++    cdef cnp.ndarray[cnp.npy_int64, mode='c', ndim=1] marker
++
++    if not rng:
++        rng = np.random.default_rng()
++
++    # idd_aidi
++    L = krank + 8
++    n2 = 0
++    if (L >= n2) or (L > m):
++        inds, proj = iddr_id(a, krank)
++        return inds, proj
++
++    n2 = idd_poweroftwo(m)
++
++    # idd_sfrmi
++    # idd_pairsamps
++    ind = rng.permutation(n2)
++    ind2 = cnp.PyArray_ZEROS(1, [L], cnp.NPY_INT64, 0)
++
++    marker = cnp.PyArray_ZEROS(1, [n2//2], cnp.NPY_INT64, 0)
++    for k in range(L):
++        marker[(ind[k]+1)//2] = marker[(ind[k]+1)//2]+1
++
++    for r in range(n2//2):
++        if marker[r] != 0:
++            l2 += 1
++            ind2[r] = r
++
++    # Draw (nsteps x m x 2) arrays from [-1, 1) uniformly and scale
++    # each 2-element row to unity norm
++    albetas = rng.uniform(low=-1.0, high=1.0, size=[nsteps, m, 2])
++    aa = cnp.PyArray_DATA(albetas)
++    # Walk over every 2D row and normalize
++    for r in range(0, 2*nsteps*m, 2):
++        # ignoring the improbable zero generation by rng.uniform
++        h = 1.0/hypot(aa[r], aa[r+1])
++        aa[r] *= h
++        aa[r+1] *= h
++
++    # idd_random_transf
++    rta = a.copy()
++
++    # Rotate and shuffle "a" nsteps-many times
++    giv2x2 = cnp.PyArray_ZEROS(2, [2, 2], cnp.NPY_FLOAT64, 0)
++    for nstep in range(nsteps):
++        for row in range(m-1):
++            alpha, beta = albetas[nstep, row, 0], albetas[nstep, row, 1]
++            giv2x2[0, 0] = alpha
++            giv2x2[0, 1] = beta
++            giv2x2[1, 0] = -beta
++            giv2x2[1, 1] = alpha
++            np.matmul(giv2x2, rta[row:row+2, :], out=rta[row:row+2, :])
++
++        rta = rta[rng.permutation(m), :]
++
++    # idd_subselect pick randomly n2-many rows
++    subselect = rng.choice(m, n2, replace=False)
++    rta = rta[subselect, :]
++
++    # idd_sffti
++    twopi = 2*np.pi
++    twopii = twopi*1.j
++    nblock = idd_ldiv(l2, n2)
++    fact = 1/np.sqrt(n2)
++
++    if l2 == 1:
++        wsave = np.exp(-twopii*k*ind2[0]/np.arange(1, n2+1))*fact
++    else:
++        m = n2//nblock
++
++        wsave = np.empty(m*l2, dtype=complex)
++        for j in range(l2):
++            i = ind2[j]
++            if (i+1) <= (n//2 - m//2):
++                idivm = i // m
++                imodm = i - m*idivm
++                for k in range(m):
++                    wsave[m*j+k] = (
++                        np.exp(-twopii*(k)*imodm/m)*
++                        np.exp(-twopii*(k)*(idivm+1)/n)*
++                        fact
++                        )
++            else:
++                idivm = (i+1)//(m//2)
++                imodm = (i+1)-(m//2)*idivm
++                for k in range(m):
++                    wsave[m*j+k] = np.exp(-twopii*(k-1)*imodm/m)*fact
++
++    # idd_sfft.f
++    # There is some significant index olympics happening in the original Fortran code
++    # however I could not reverse engineer it to understand what is happening and kept
++    # as is with all its cryptic movements and their performance hits.
++    # See DOI:10.1016/j.acha.2007.12.002 - Section 3.3
++
++    # Perform partial FFT to each nblock
++    F = rfft(rta.reshape(nblock, m, -1), order='F', axis=0)
++    # Roll the first entry to the last in the first axis for
++    # the real frequency components. (faster than np.roll)
++    F = F[[x for x in range(1, F.shape[0])] + [0], :, :]
++    # Convert back to 2D array
++    F = F.reshape(F.shape[0]*F.shape[1], -1)
++
++    csum = np.zeros_like(F[0, :])
++    rsum = np.zeros_like(F[0, :])
++
++    for j in range(l2):
++        i = ind2[j]
++        if (i+1) <= (n//2 - m//2):
++            idivm = i // m
++            imodm = i - m*idivm
++            csum[:] = 0.0
++            for k in range(m):
++                csum += F[m*idivm+k, :] * wsave[m*j+k]
++            rta[2*i, :] = csum.real
++            rta[2*i+1, :] = csum.imag
++
++        else:
++            idivm = (i+1)//(m//2)
++            imodm = (i+1)-(m//2)*idivm
++            csum[:] = 0.0
++            for k in range(m):
++                csum += F[m*(nblock//2)+k, :] * wsave[m*j+k]
++            rta[2*i, :] = csum.real
++            rta[2*i+1, :] = csum.imag
++            if i == (n//2) - 1:
++                for k in range(m):
++                    rsum += F[m*(nblock//2)+k, :]
++                rta[n-2, :] = rsum
++                rta[n-2, :] *= fact
++
++                rsum[:] = 0.0
++                for k in range(m//2):
++                    rsum += F[m*(nblock//2)+2*k-1]
++                    rsum -= F[m*(nblock//2)+2*k]
++                rta[n-1, :] = rsum
++                rta[n-1, :] *= fact
++
++    # idd_subselect pick randomly l2-many rows
++    subselect = rng.choice(n2, l2, replace=False)
++    rta = rta[subselect, :]
++
++    perms, proj = iddr_id(rta, krank)
++
++    return perms, proj
++
++
++def iddr_asvd(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a: NDArray, int krank,
++              rng=None):
++    cdef int m = a.shape[0], n = a.shape[1]
++    cdef int info, ci
++    cdef cnp.ndarray[cnp.float64_t, mode='fortran', ndim=2] C
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau1
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau2
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] UU
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
++    cdef cnp.ndarray[cnp.float64_t, ndim=2] V
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] VV
++    cdef cnp.ndarray[cnp.float64_t, ndim=2] proj
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] perms
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] p
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] col
++
++    perms, proj = iddr_aid(a.copy(), krank=krank, rng=rng)
++
++    UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_FLOAT64, 0)
++    VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_FLOAT64, 0)
++
++    p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_FLOAT64, 0)
++    col = a[:, perms[:krank]].copy()
++
++    # idd_reconint
++    for ci in range(krank):
++        p[ci, perms[ci]] = 1.0
++
++    p[:, perms[krank:]] = proj[:, :]
++
++    inds1, tau1 = iddr_qrpiv(col, krank)
++    # idd_rinqr and idd_rearr
++    r = np.triu(col[:krank, :])
++    for ci in range(krank-1, -1, -1):
++        r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
++
++    t = p.T.copy()
++    inds2, tau2 = iddr_qrpiv(t, krank)
++    r2 = np.triu(t[:krank, :])
++    for ci in range(krank-1, -1, -1):
++        r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
++
++    r3 = r @ r2.T
++    UU[:krank, :krank], S, V = la.svd(r3, full_matrices=False)
++
++    # Apply Q of col to U from the left
++    C = col[:, :krank].copy(order='F')
++    dorm2r('R', 'T',
++           &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
++           &UU[0,0], &krank, &a[0, 0], &info)
++
++    VV[:krank, :krank] = V[:, :].T
++    # Apply Q of t to V from the left
++    C = t[:, :krank].copy(order='F')
++    dorm2r('R', 'T',
++           &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
++           &VV[0, 0], &krank, &a[0, 0], &info)
++
++    return UU, S, VV
++
++
++def iddr_id(cnp.ndarray[cnp.float64_t, ndim=2] a, int krank):
++    cdef int n = a.shape[1]
++    cdef int tmp_int
++    cdef cnp.float64_t one = 1.0
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] perms
++
++    inds, _ = iddr_qrpiv(a, krank)
++    perms = cnp.PyArray_Arange(0, n, 1, cnp.NPY_INT64)
++
++    if krank > 0:
++        for p in range(krank):
++            # Apply pivots
++            tmp_int = perms[p]
++            perms[p] = perms[inds[p]]
++            perms[inds[p]] = tmp_int
++
++    # See iddp_id comments for below
++    tmp_int = n - krank
++    # SIDE,UPLO,TRANSA,DIAG,M,N,ALPHA,A,LDA,B,LDB
++    dtrsm('R', 'L', 'N', 'N',
++          &tmp_int, &krank, &one, &a[0, 0], &n, &a[0, krank], &n)
++
++    return perms, a[:krank, krank:]
++
++
++def iddr_qrpiv(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a: NDArray, krank: int):
++    cdef int m = a.shape[0], n = a.shape[1]
++    cdef cnp.ndarray col_norms = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
++    cdef int loop = 0, loops, kpiv = 0, i = 0, tmp_int = 0, int_n = 0
++    cdef cnp.float64_t tmp_sca = 0.
++    cdef cnp.ndarray taus = cnp.PyArray_ZEROS(1, [m], cnp.NPY_FLOAT64, 0)
++    cdef cnp.ndarray ind = cnp.PyArray_ZEROS(1, [n], cnp.NPY_INT64, 0)
++    cdef cnp.float64_t[::1] taus_v = taus
++    cdef cnp.float64_t feps = 0.1e-16  # np.finfo(np.float64).eps
++    cdef cnp.float64_t ssmax, ssmaxin
++    cdef int nupdate = 0
++
++    loops = min(krank, min(m, n))
++    for i in range(n):
++        col_norms[i] = dnrm2(&m, &a[0, i], &n)**2
++
++    kpiv = np.argmax(col_norms)
++    ssmax = col_norms[kpiv]
++    ssmaxin = ssmax
++
++    for loop in range(loops):
++
++        ind[loop] = kpiv
++        # Swap columns a[:, k] and a[:, kpiv]
++        a[:, [kpiv, loop]] = a[:, [loop, kpiv]]
++        # Swap col_norms[krank] and col_norms[kpiv]
++        col_norms[[kpiv, loop]] = col_norms[[loop, kpiv]]
++
++        if loop < m-1:
++            tmp_sca = a[loop, loop]
++            # FIX: Convert these to F_INT
++            tmp_int = (m - loop)
++            int_n = n
++            dlarfgp(&tmp_int, &tmp_sca, &a[loop+1, loop], &int_n, &taus_v[loop])
++
++            # Overwrite with 1. for easy matmul
++            a[loop, loop] = 1
++            if loop < n-1:
++                # Apply the householder reflector to the rest on the right
++                a[loop:, loop+1:] -= np.outer(taus[loop]*a[loop:, loop],
++                                              a[loop:, loop] @ a[loop:, loop+1:])
++
++            # Put back the beta in place
++            a[loop, loop] = tmp_sca
++
++            # Update the norms
++            col_norms[loop] = 0
++            col_norms[loop+1:] -= a[loop, loop+1:]**2
++            ssmax = 0
++            kpiv = loop+1
++
++            if loop < n-1:
++                kpiv = np.argmax(col_norms[loop+1:]) + (loop + 1)
++                ssmax = col_norms[kpiv]
++            if (((ssmax < 1000*feps*ssmaxin) and (nupdate == 0)) or
++                    ((ssmax < ((1000*feps)**2)*ssmaxin) and (nupdate == 1))):
++                nupdate += 1
++                ssmax = 0
++                kpiv = loop+1
++
++                if loop < n-1:
++                    for i in range(loop+1, n):
++                        tmp_int = m-loop-1
++                        col_norms[i] = dnrm2(&tmp_int, &a[loop+1, i], &n)**2
++                    kpiv = np.argmax(col_norms[loop+1:]) + (loop + 1)
++                    ssmax = col_norms[kpiv]
++
++    return ind, taus
++
++
++def iddr_rid(A: LinearOperator, int krank, rng=None):
++    cdef int m = A.shape[0], n = A.shape[1], k = 0
++    cdef int L = min(krank+2, min(m, n))
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] r
++
++    if not rng:
++        rng = np.random.default_rng()
++
++    r = cnp.PyArray_EMPTY(2, [L, n], cnp.NPY_FLOAT64, 0)
++    for k in range(L):
++        r[k, :] = A.rmatvec(rng.uniform(size=m))
++
++    return iddr_id(a=r, krank=krank)
++
++
++def iddr_rsvd(A: LinearOperator, int krank, rng=None):
++    cdef int n = A.shape[1], j
++    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms
++    cdef cnp.ndarray[cnp.float64_t, ndim=2] proj
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] col
++
++    perms, proj = iddr_rid(A, krank, rng)
++    # idd_getcols
++    col = cnp.PyArray_EMPTY(2, [n, krank], cnp.NPY_FLOAT64, 0)
++    x = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
++    for j in range(krank):
++        x[perms[j]] = 1.
++        col[:, j] = A.matvec(x)
++        x[perms[j]] = 0.
++
++    return idd_id2svd(cols=col, perms=perms, proj=proj)
++
++
++def iddr_svd(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a: NDArray, int krank):
++    cdef int m = a.shape[0], info = 0
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] taus
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] UU
++    cdef cnp.ndarray[cnp.float64_t, mode='fortran', ndim=2] C
++
++    # Get the pivoted QR
++    inds, taus = iddr_qrpiv(a, krank)
++
++    r = np.triu(a[:krank, :])
++    # Apply pivots in reverse
++    for p in range(krank-1, -1, -1):
++        r[:, [p, inds[p]]] = r[:, [inds[p], p]]
++
++    # JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO
++    # dgesvd('S', 'O', &krank, &n)
++    U, S, V = la.svd(r, full_matrices=False)
++
++    # Apply Q to U via dorm2r
++    # Possibly U is shorter than Q
++    UU = np.zeros([m, krank], dtype=a.dtype)
++    UU[:krank, :krank] = U
++    # Do the transpose dance for C-layout, use a for scratch
++    C = a[:, :krank].copy(order='F')
++    dorm2r('R', 'T',
++           &krank, &m, &krank, &C[0, 0], &m, &taus[0],
++           &UU[0,0], &krank, &a[0, 0], &info)
++
++    return UU, S, V
++
++
++def idz_diffsnorm(A: LinearOperator, B: LinearOperator, int its=20, rng=None):
++    cdef int n = A.shape[1], j = 0, intone = 1
++    cdef cnp.float64_t snorm = 0.0
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] v1
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] v2
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] u1
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] u2
++
++    if not rng:
++        rng = np.random.default_rng()
++    v1 = rng.uniform(low=-1, high=1, size=(n, 2)).view(np.complex128).ravel()
++    v1 /= dznrm2(&n, &v1[0], &intone)
++
++    for j in range(its):
++        u1 = A.matvec(v1)
++        u2 = B.matvec(v1)
++        u1 -= u2
++        v1 = A.rmatvec(u1)
++        v2 = B.rmatvec(u1)
++        v1 -= v2
++
++        snorm = dznrm2(&n, &v1[0], &intone)
++        if snorm > 0.0:
++            v1 /= snorm
++
++        snorm = np.sqrt(snorm)
++
++    return snorm
++
++
++def idz_estrank(cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] a: NDArray, eps: float,
++                rng=None):
++    cdef int m = a.shape[0], n = a.shape[1], n2, nsteps = 3, row, r, nstep, cols, k
++    cdef cnp.float64_t h, alpha, beta
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=3] albetas
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau_arr
++    cdef cnp.ndarray[cnp.npy_int64, mode='c', ndim=1] subselect
++    cdef double complex[:, ::1] ff
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] giv2x2
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] rta
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] F
++
++    if not rng:
++        rng = np.random.default_rng()
++
++    n2 = idd_poweroftwo(m)
++    # This part is the initialization that is done via idz_frmi
++    # for a Subsampled Randomized Fourier Transfmrom (SRFT).
++
++    # Draw (nsteps x m x 4) array from [0, 2)*pi uniformly for
++    # random points on complex unit circle and unitary rotations
++    albetas = np.empty([nsteps, m, 4])
++    albetas[:, :, 2:] = rng.uniform(low=0.0, high=2.0, size=[nsteps, m, 2])
++    albetas[:, :, 2:] *= np.pi
++    np.cos(albetas[:, :, 2], out=albetas[:, :, 0])
++    np.sin(albetas[:, :, 2], out=albetas[:, :, 1])
++    np.cos(albetas[:, :, 3], out=albetas[:, :, 2])
++    np.sin(albetas[:, :, 3], out=albetas[:, :, 3])
++
++    # idd_random_transf
++    rta = a.copy()
++
++    # Rotate and shuffle "a" nsteps-many times
++    giv2x2 = cnp.PyArray_ZEROS(2, [2, 2], cnp.NPY_FLOAT64, 0)
++    for nstep in range(nsteps):
++        # Multiply with a point on the unit circle
++        rta *= albetas[nstep, :, 2:].view(np.complex128)
++        # Rotate
++        for row in range(m-1):
++            alpha, beta = albetas[nstep, row, 0], albetas[nstep, row, 1]
++            giv2x2[0, 0] = alpha
++            giv2x2[0, 1] = beta
++            giv2x2[1, 0] = -beta
++            giv2x2[1, 1] = alpha
++            np.matmul(giv2x2, rta[row:row+2, :], out=rta[row:row+2, :])
++
++        rta = rta[rng.permutation(m), :]
++
++    # idd_subselect pick randomly n2-many rows
++    subselect = rng.choice(m, n2, replace=False)
++    rta = rta[subselect, :]
++    # Perform rfft on each column.
++    F = fft(rta, axis=0)[rng.permutation(n2), :]
++
++    Fcopy = F.copy()
++    cols = F.shape[1]
++    row = F.shape[0]
++    sssmax = 0.
++
++    for r in range(cols):
++        h = dznrm2(&row, &F[0, r], &cols)
++        if h > sssmax:
++            sssmax = h
++
++    tau_arr = cnp.PyArray_ZEROS(1, [cols], cnp.NPY_COMPLEX128, 0)
++    k, nulls = 0, 0
++    ff = F
++    # Loop until nulls = 7, or krank+nulls = n2, or krank+nulls = n.
++    while (nulls < 7) and (k+nulls < min(n, n2)):
++        # Apply previous Householder reflectors
++        if k > 0:
++            for kk in range(k):
++                F[k, kk:] -= (
++                    np.conj(tau_arr[kk])*
++                    (F[kk, kk:].conj() @ F[k, kk:])*
++                    F[kk, kk:]
++                    )
++
++        # Get the next Householder reflector and store in F
++        r = cols-k
++        row = 1
++        zlarfgp(&r, &ff[k, k], &ff[k, k+1], &row, &tau_arr[k])
++        if (np.abs(F[k, k]) <= eps*sssmax):
++            nulls += 1
++        F[k, k] = 1
++        k += 1
++
++    if nulls < 7:
++        k = 0
++
++    return k, Fcopy
++
++
++def idz_findrank(A: LinearOperator, cnp.float64_t eps, rng=None):
++    # Estimate the rank of A by repeatedly using A.rmatvec(random vec)
++
++    cdef int m = A.shape[0], n = A.shape[1], k = 0, kk = 0,r = n, krank
++    cdef int no_of_cols = 4, intone = 1, info = 0
++    cdef cnp.complex128_t[::1] tau = cnp.PyArray_ZEROS(1, [min(m, n)],
++                                                       cnp.NPY_COMPLEX128, 0)
++    cdef cnp.complex128_t[::1] y = cnp.PyArray_ZEROS(1, [n], cnp.NPY_COMPLEX128, 0)
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] retarr
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] x
++
++    # The size of the QR decomposition is rank dependent which is unknown
++    # at runtime. Hence we don't want to allocate a dense version of the
++    # linear operator which can be too big. Instead, a typical "realloc double
++    # if run out of space" strategy is used here. Starts with 4*n
++    # Also, we hold the A.T @ x results in a separate array to return
++    # and do the same for that too.
++    cdef cnp.complex128_t *ra = PyMem_Malloc(
++        sizeof(cnp.complex128_t)*no_of_cols*n
++        )
++    cdef cnp.complex128_t *reallocated_ra
++    cdef cnp.complex128_t *ret = PyMem_Malloc(
++        sizeof(cnp.complex128_t)*no_of_cols*n
++        )
++    cdef cnp.complex128_t *reallocated_ret
++    cdef cnp.complex128_t enorm = 0.0
++
++    if (not ra) or (not ret):
++        raise MemoryError("Failed to allocate at least required memory "
++                          f"{no_of_cols*n*8} bytes for"
++                          "'scipy.linalg.interpolative.idz_findrank()' "
++                          "function.")
++
++    if not rng:
++        rng = np.random.default_rng()
++
++    krank = 0
++    try:
++        while True:
++
++            # Generate random vector and rmatvec then save the result
++            x = rng.uniform(size=(m,2)).view(np.complex128).ravel()
++            y = A.rmatvec(x)
++
++            for kk in range(n):
++                ret[krank*n + kk] = y[kk]
++
++            if krank == 0:
++                enorm = dznrm2(&n, &y[0], &intone)
++            else:  # krank > 0
++                # Transpose-Apply previous Householder reflectors, if any
++                # SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, WORK, INFO
++                zunm2r('L','C', &n, &intone, &krank, &ra[0], &n,
++                       &tau[0], &y[0], &n, &ra[(no_of_cols-1)*n], &info)
++
++            # Get the next Householder reflector
++            r = n-krank
++            # N, ALPHA, X, INCX, TAU
++            zlarfgp(&r, &y[krank], &y[krank+1], &intone, &tau[krank])
++
++            for kk in range(n):
++                ra[krank*n + kk] = y[kk]
++
++            # Running out of space; try to double the size of ra
++            if krank == (no_of_cols-2):
++                reallocated_ra = PyMem_Realloc(
++                    ra, sizeof(cnp.complex128_t)*no_of_cols*n*2)
++                reallocated_ret = PyMem_Realloc(
++                    ret, sizeof(cnp.complex128_t)*no_of_cols*n*2)
++
++                if reallocated_ra and reallocated_ret:
++                    ra = reallocated_ra
++                    ret = reallocated_ret
++                    no_of_cols *= 2
++                else:
++                    raise MemoryError(
++                        "'scipy.linalg.interpolative.idz_findrank()' failed to "
++                        f"allocate the required memory,{no_of_cols*n*16} bytes "
++                        "while trying to determine the rank (currently "
++                        f"{krank}) of a LinearOperator with precision {eps}."
++                    )
++            krank += 1
++            if (np.abs(y[krank-1]) < eps*enorm) or (krank >= min(m, n)):
++                break
++    finally:
++        # Crashed or successfully ended up here
++        # Discard Householder vectors
++        PyMem_Free(ra)
++        retarr = cnp.PyArray_EMPTY(2, [krank, n], cnp.NPY_COMPLEX128, 0)
++        for k in range(krank):
++            for kk in range(n):
++                retarr[k, kk] = ret[k*n+kk]
++        PyMem_Free(ret)
++
++    return krank, retarr
++
++
++def idz_id2svd(
++    cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] cols,
++    cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms,
++    cnp.ndarray[cnp.complex128_t, ndim=2] proj,
++    ):
++    cdef int m = cols.shape[0], krank = cols.shape[1]
++    cdef int n = proj.shape[1] + krank, info, ci
++    cdef cnp.ndarray[cnp.complex128_t, mode='fortran', ndim=2] C
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau1
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau2
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] UU
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
++    cdef cnp.ndarray[cnp.complex128_t, ndim=2] V
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] VV
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] p
++
++    if krank > 0:
++        UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_COMPLEX128, 0)
++        VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_COMPLEX128, 0)
++        p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_COMPLEX128, 0)
++
++        # idd_reconint
++        for ci in range(krank):
++            p[ci, perms[ci]] = 1.0
++
++        p[:, perms[krank:]] = proj[:, :]
++        inds1, tau1 = idzr_qrpiv(cols, krank)
++        # idz_rinqr and idz_rearr
++        r = np.triu(cols[:krank, :])
++        for ci in range(krank-1, -1, -1):
++            r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
++
++        t = p.T.conj().copy()
++        inds2, tau2 = idzr_qrpiv(t, krank)
++        r2 = np.triu(t[:krank, :])
++        for ci in range(krank-1, -1, -1):
++            r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
++
++        r3 = r @ r2.T.conj()
++        UU[:krank, :krank], S, V = la.svd(r3, full_matrices=False)
++
++        # Apply Q of col to U from the left
++        # But do the adjoint dance for LAPACK via U.H @ Q.H
++        np.conjugate(tau1, out=tau1)
++        C = cols[:, :krank].conj().copy(order='F')
++        zunm2r('R', 'C',
++            &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
++            &UU[0,0], &krank, &cols[0, 0], &info)
++
++        VV[:krank, :krank] = V[:, :].conj().T
++
++        # Apply Q of t to V from the left
++        # But do the adjoint dance for LAPACK via V.H @ Q.H
++        np.conjugate(tau2, out=tau2)
++        C = t[:, :krank].conj().copy(order='F')
++        zunm2r('R', 'C',
++            &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
++            &VV[0, 0], &krank, &cols[0, 0], &info)
++
++    return UU, S, VV
++
++
++def idz_reconid(B, idx, proj):
++    cdef int m = B.shape[0], krank = B.shape[1]
++    cdef int n = len(idx)
++    approx = np.zeros([m, n], dtype=np.complex128)
++
++    approx[:, idx[:krank]] = B
++    approx[:, idx[krank:]] = B @ proj
++
++    return approx
++
++
++def idz_snorm(A: LinearOperator, int its=20, rng=None):
++    cdef int n = A.shape[1]
++    cdef int j = 0, intone = 1
++    cdef cnp.float64_t snorm = 0.0
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] v
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] u
++
++    if not rng:
++        rng = np.random.default_rng()
++
++    v = rng.uniform(low=-1, high=1, size=(n, 2)).view(np.complex128).ravel()
++    v /= dznrm2(&n, &v[0], &intone)
++
++    for j in range(its):
++        u = A.matvec(v)
++        v = A.rmatvec(u)
++        snorm = dznrm2(&n, &v[0], &intone)
++        if snorm > 0.0:
++            v /= snorm
++
++        snorm = np.sqrt(snorm)
++
++    return snorm
++
++
++def idzp_aid(cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] a: NDArray, eps: float,
++             rng=None):
++    krank, proj = idz_estrank(a, eps=eps, rng=rng)
++    if krank != 0:
++        proj = proj[:krank, :]
++        return idzp_id(proj, eps=eps)
++
++    return idzp_id(a, eps=eps)
++
++
++def idzp_asvd(cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] a, cnp.float64_t eps,
++              rng=None):
++    cdef int m = a.shape[0], n = a.shape[1]
++    cdef int krank, info, ci
++    cdef cnp.ndarray[cnp.complex128_t, mode='fortran', ndim=2] C
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau1
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau2
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] UU
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
++    cdef cnp.ndarray[cnp.complex128_t, ndim=2] V
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] VV
++    cdef cnp.ndarray[cnp.complex128_t, ndim=2] proj
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] perms
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] p
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] col
++
++    krank, perms, proj = idzp_aid(a.copy(), eps, rng)
++
++    if krank > 0:
++        UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_COMPLEX128, 0)
++        VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_COMPLEX128, 0)
++        p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_COMPLEX128, 0)
++        col = a[:, perms[:krank]].copy()
++
++        # idd_reconint
++        for ci in range(krank):
++            p[ci, perms[ci]] = 1.0
++
++        p[:, perms[krank:]] = proj[:, :]
++        inds1, tau1 = idzr_qrpiv(col, krank)
++        # idz_rinqr and idz_rearr
++        r = np.triu(col[:krank, :])
++        for ci in range(krank-1, -1, -1):
++            r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
++
++        t = p.T.conj().copy()
++        inds2, tau2 = idzr_qrpiv(t, krank)
++        r2 = np.triu(t[:krank, :])
++        for ci in range(krank-1, -1, -1):
++            r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
++
++        r3 = r @ r2.T.conj()
++        UU[:krank, :krank], S, V = la.svd(r3, full_matrices=False)
++
++        # Apply Q of col to U from the left
++        # But do the adjoint dance for LAPACK via U.H @ Q.H
++        np.conjugate(tau1, out=tau1)
++        C = col[:, :krank].conj().copy(order='F')
++        zunm2r('R', 'C',
++            &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
++            &UU[0,0], &krank, &a[0, 0], &info)
++
++        VV[:krank, :krank] = V[:, :].conj().T
++
++        # Apply Q of t to V from the left
++        # But do the adjoint dance for LAPACK via V.H @ Q.H
++        np.conjugate(tau2, out=tau2)
++        C = t[:, :krank].conj().copy(order='F')
++        zunm2r('R', 'C',
++            &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
++            &VV[0, 0], &krank, &a[0, 0], &info)
++
++    return UU, S, VV
++
++
++def idzp_id(cnp.ndarray[cnp.complex128_t, mode="c", ndim=2] a, cnp.float64_t eps):
++    cdef int n = a.shape[1], krank, tmp_int, p
++    cdef double complex one = 1
++    krank, _, inds = idzp_qrpiv(a, eps)
++
++    # Change pivots to permutation
++    perms = cnp.PyArray_Arange(0, n, 1, cnp.NPY_INT64)
++
++    if krank > 0:
++        for p in range(krank):
++            # Apply pivots
++            tmp_int = perms[p]
++            perms[p] = perms[inds[p]]
++            perms[inds[p]] = tmp_int
++
++    tmp_int = n - krank
++    # SIDE,UPLO,TRANSA,DIAG,M,N,ALPHA,A,LDA,B,LDB
++    ztrsm('R', 'L', 'N', 'N',
++          &tmp_int, &krank, &one, &a[0, 0], &n, &a[0, krank], &n)
++
++    return krank, perms, a[:krank, krank:]
++
++
++def idzp_qrpiv(cnp.ndarray[cnp.complex128_t, mode="c", ndim=2] a, cnp.float64_t eps):
++    cdef int m = a.shape[0], n = a.shape[1]
++    cdef cnp.ndarray col_norms = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
++    cdef int k = 0, kpiv = 0, i = 0, tmp_int = 0, int_n = 0
++    cdef double complex tmp_sca = 0.
++    cdef cnp.ndarray taus = cnp.PyArray_ZEROS(1, [m], cnp.NPY_COMPLEX128, 0)
++    cdef cnp.ndarray ind = cnp.PyArray_ZEROS(1, [n], cnp.NPY_INT64, 0)
++    cdef double complex[::1] taus_v = taus
++    cdef cnp.float64_t feps = 0.1e-16  # Smaller than np.finfo(np.float64).eps
++    cdef cnp.float64_t ssmax, ssmaxin
++    cdef int nupdate = 0
++
++    for i in range(n):
++        col_norms[i] = dznrm2(&m, &a[0, i], &n)**2
++
++    kpiv = np.argmax(col_norms)
++    ssmax = col_norms[kpiv]
++    ssmaxin = ssmax
++
++    for k in range(min(m, n)):
++
++        # Pivoting
++        ind[k] = kpiv
++        # Swap columns a[:, k] and a[:, kpiv]
++        a[:, [kpiv, k]] = a[:, [k, kpiv]]
++
++        # Swap col_norms[krank] and col_norms[kpiv]
++        col_norms[[kpiv, k]] = col_norms[[k, kpiv]]
++
++        if k < m-1:
++            # Compute the householder reflector for column k
++            tmp_sca = a[k, k]
++            # FIX: Convert these to F_INT
++            tmp_int = (m - k)
++            int_n = n
++            zlarfgp(&tmp_int, &tmp_sca, &a[k+1, k], &int_n, &taus_v[k])
++
++            # Overwrite with 1. for easy matmul
++            a[k, k] = 1.0
++            if k < n-1:
++                # Apply the householder reflector to the rest on the right.
++                # Note! Tau returned by zlarfgp is complex valued and thus,
++                # reflector is not Hermitian, hence the conjugates. See the
++                # documentation of zlarfgp.
++                a[k:, k+1:] -= np.outer(taus[k].conj()*a[k:, k],
++                                        a[k:, k].conj() @ a[k:, k+1:]
++                                        )
++
++            # Put back the beta in place
++            a[k, k] = tmp_sca
++            # Update the norms
++            col_norms[k] = 0
++            col_norms[k+1:] -= (a[k, k+1:] * a[k, k+1:].conj()).real
++            ssmax = 0.0
++            kpiv = k+1
++
++            if k < n-1:
++                kpiv = np.argmax(col_norms[k+1:]) + (k + 1)
++                ssmax = col_norms[kpiv]
++
++            if (((ssmax < 1000*feps*ssmaxin) and (nupdate == 0)) or
++                    ((ssmax < ((1000*feps)**2)*ssmaxin) and (nupdate == 1))):
++                nupdate += 1
++                ssmax = 0
++                kpiv = k+1
++                if k < n-1:
++                    for i in range(k+1, n):
++                        tmp_int = m-k-1
++                        col_norms[i] = dznrm2(&tmp_int, &a[k+1, i], &n)**2
++                    kpiv = np.argmax(col_norms[k+1:]) + (k + 1)
++                    ssmax = col_norms[kpiv]
++        if (ssmax <= (eps**2)*ssmaxin):
++            break
++    # a is overwritten; return numerical rank and pivots
++
++    return k+1, taus, ind
++
++
++def idzp_rid(A: LinearOperator, cnp.float64_t eps, rng=None):
++    _, ret = idz_findrank(A, eps, rng=rng)
++    return idzp_id(ret, eps=eps)
++
++
++def idzp_rsvd(A: LinearOperator, cnp.float64_t eps, rng=None):
++    cdef int n = A.shape[1]
++    cdef int krank, j
++    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms
++    cdef cnp.ndarray[cnp.complex128_t, ndim=2] proj
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] col
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] x
++
++    krank, perms, proj = idzp_rid(A, eps, rng=rng)
++
++    if krank > 0:
++        # idd_getcols
++        col = cnp.PyArray_EMPTY(2, [n, krank], cnp.NPY_COMPLEX128, 0)
++        x = cnp.PyArray_ZEROS(1, [n], cnp.NPY_COMPLEX128, 0)
++
++        for j in range(krank):
++            x[perms[j]] = 1.
++            col[:, j] = A.matvec(x)
++            x[perms[j]] = 0.
++
++        return idz_id2svd(cols=col, perms=perms, proj=proj)
++
++    # TODO: figure out empty return
++    return None
++
++
++def idzp_svd(cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] a, cnp.float64_t eps):
++    cdef int m = a.shape[0], krank, info
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] taus
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] UU
++    cdef cnp.ndarray[cnp.complex128_t, ndim=2] V
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] r
++    cdef cnp.ndarray[cnp.complex128_t, mode='fortran', ndim=2] C
++    cdef cnp.ndarray[cnp.float64_t, ndim=1] S
++
++    # Get the pivoted QR
++    krank, taus, inds = idzp_qrpiv(a, eps)
++    UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_COMPLEX128, 0)
++
++    if krank > 0:
++        r = np.triu(a[:krank, :])
++
++        for p in range(krank-1, -1, -1):
++            r[:, [p, inds[p]]] = r[:, [inds[p], p]]
++
++        UU[:krank, :krank], S, V = la.svd(r, full_matrices=False)
++        # Apply Q to U via zunm2r
++        np.conjugate(taus, out=taus)
++        # But do the adjoint dance for LAPACK via U.H @ Q.H; use a for scratch
++        C = a[:, :krank].conj().copy(order='F')
++        zunm2r('R', 'C',
++               &krank, &m, &krank, &C[0, 0], &m, &taus[0],
++               &UU[0,0], &krank, &a[0, 0], &info)
++
++    return UU, S, V
++
++
++def idzr_aid(cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] a: NDArray, int krank,
++             rng=None):
++    cdef int m = a.shape[0], n2, L, nblock, nsteps = 3, mb
++    cdef cnp.float64_t twopi = 2*np.pi, fact
++    cdef double complex twopii = twopi*1.j
++    cdef cnp.ndarray[cnp.npy_int64, mode='c', ndim=1] ind
++    cdef cnp.ndarray[cnp.npy_int64, mode='c', ndim=1] subselect
++    cdef cnp.ndarray[cnp.npy_float64, mode='c', ndim=1] dm1
++    cdef cnp.ndarray[cnp.npy_float64, mode='c', ndim=1] dm2
++    cdef cnp.ndarray[cnp.npy_float64, mode='c', ndim=3] albetas
++    cdef cnp.ndarray[cnp.npy_float64, mode='c', ndim=2] rta
++    cdef cnp.ndarray[cnp.npy_float64, mode='c', ndim=2] giv2x2
++
++    if not rng:
++        rng = np.random.default_rng()
++
++    n2 = 0
++    L = krank + 8
++    if (L >= n2) or (L > m):
++        inds, proj = idzr_id(a, krank)
++        return inds, proj
++
++    n2 = idd_poweroftwo(m)
++    # This part is the initialization that is done via idz_frmi
++    # for a Subsampled Randomized Fourier Transfmrom (SRFT).
++
++    # Draw (nsteps x m x 4) array from [0, 2)*pi uniformly for
++    # random points on complex unit circle and unitary rotations
++    albetas = np.empty([nsteps, m, 4])
++    albetas[:, :, 2:] = rng.uniform(low=0.0, high=2.0, size=[nsteps, m, 2])
++    albetas[:, :, 2:] *= np.pi
++    np.cos(albetas[:, :, 2], out=albetas[:, :, 0])
++    np.sin(albetas[:, :, 2], out=albetas[:, :, 1])
++    np.cos(albetas[:, :, 3], out=albetas[:, :, 2])
++    np.sin(albetas[:, :, 3], out=albetas[:, :, 3])
++
++    # idd_random_transf
++    rta = a.copy()
++
++    # Rotate and shuffle "a" nsteps-many times
++    giv2x2 = np.array([[0., 0. ], [0., 0.]])
++    for nstep in range(nsteps):
++        # Multiply with a point on the unit circle
++        rta *= albetas[nstep, :, 2:].view(np.complex128)
++        # Rotate
++        for row in range(m-1):
++            alpha, beta = albetas[nstep, row, 0], albetas[nstep, row, 1]
++            giv2x2[0, 0] = alpha
++            giv2x2[0, 1] = beta
++            giv2x2[1, 0] = -beta
++            giv2x2[1, 1] = alpha
++            np.matmul(giv2x2, rta[row:row+2, :], out=rta[row:row+2, :])
++
++        rta = rta[rng.permutation(m), :]
++
++    # idd_subselect pick randomly n2-many rows
++    subselect = rng.choice(m, n2, replace=False)
++    rta = rta[subselect, :]
++    ind = rng.choice(n2, L, replace=False)
++
++    nblock = idd_ldiv(L, n2)
++    mb = n2 // nblock
++    fact = 1.0 / np.sqrt(n2)
++
++    # Create (L x mb) DFT matrix
++    # wsave = np.empty([L, mb], dtype=np.complex128)
++    dm1, dm2 = np.divmod(ind, mb, dtype=np.float64)
++    dm1 /= n2
++    dm1 += dm2 / mb
++    wsave = np.outer(dm1, -twopii*np.arange(mb))
++    np.exp(wsave, out=wsave)
++    wsave *= fact
++
++    # Perform partial FFT to each nblock then swap first two axes for transposition
++    # and subsample by ind // mb. This is basically a few options combined into one
++    # First we view each column as (nblock x mb) then take fft of each mb-long chunk.
++    # Then we transpose and multiply with DFT matrix and subselect.
++    # See DOI:10.1016/j.acha.2007.12.002 - Section 3.3
++
++    # Original fortran code does this single column at a time. We do a bit of array
++    # manipulation to do it in one go for all columns at once.
++    F = np.swapaxes(
++          fft(rta.reshape(nblock, mb, -1, order='F'), axis=0), 0, 1
++          )[:, ind // mb, :]
++    # Perform direct calculation with DFT matrix
++    V = np.einsum('ij,jim->im', wsave, F)
++
++    return idzr_id(V, krank)
++
++
++def idzr_asvd(cnp.ndarray[cnp.complex128_t, mode="c", ndim=2] a, int krank, rng=None):
++    cdef int m = a.shape[0], n = a.shape[1]
++    cdef int info, ci
++    cdef cnp.ndarray[cnp.complex128_t, mode='fortran', ndim=2] C
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau1
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau2
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] UU
++    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
++    cdef cnp.ndarray[cnp.complex128_t, ndim=2] V
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] VV
++    cdef cnp.ndarray[cnp.complex128_t, ndim=2] proj
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] perms
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
++    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] p
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] col
++    UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_COMPLEX128, 0)
++    VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_COMPLEX128, 0)
++    p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_COMPLEX128, 0)
++
++    perms, proj = idzr_aid(a.copy(), krank=krank, rng=rng)
++    col = a[:, perms[:krank]].copy()
++
++    # idd_reconint
++    for ci in range(krank):
++        p[ci, perms[ci]] = 1.0
++
++    p[:, perms[krank:]] = proj[:, :]
++    inds1, tau1 = idzr_qrpiv(col, krank)
++    # idz_rinqr and idz_rearr
++    r = np.triu(col[:krank, :])
++    for ci in range(krank-1, -1, -1):
++        r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
++
++    t = p.T.conj().copy()
++    inds2, tau2 = idzr_qrpiv(t, krank)
++    r2 = np.triu(t[:krank, :])
++    for ci in range(krank-1, -1, -1):
++        r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
++
++    r3 = r @ r2.T.conj()
++    UU[:krank, :krank], S, V = la.svd(r3, full_matrices=False)
++
++    # Apply Q of col to U from the left
++    # But do the adjoint dance for LAPACK via U.H @ Q.H
++    np.conjugate(tau1, out=tau1)
++    C = col[:, :krank].conj().copy(order='F')
++    zunm2r('R', 'C',
++           &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
++           &UU[0,0], &krank, &a[0, 0], &info)
++
++    VV[:krank, :krank] = V[:, :].conj().T
++
++    # Apply Q of t to V from the left
++    # But do the adjoint dance for LAPACK via V.H @ Q.H
++    np.conjugate(tau2, out=tau2)
++    C = t[:, :krank].conj().copy(order='F')
++    zunm2r('R', 'C',
++           &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
++           &VV[0, 0], &krank, &a[0, 0], &info)
++
++    return UU, S, VV
++
++
++def idzr_id(cnp.ndarray[cnp.complex128_t, ndim=2] a, int krank):
++    cdef int n = a.shape[1], tmp_int, p
++    cdef double complex one = 1.0
++    cdef cnp.ndarray[cnp.int64_t, ndim=1] inds
++    cdef cnp.ndarray[cnp.int64_t, ndim=1] perms
++
++    inds, _ = idzr_qrpiv(a, krank)
++    perms = cnp.PyArray_Arange(0, n, 1, cnp.NPY_INT64)
++
++    if krank > 0:
++        for p in range(krank):
++            # Apply pivots
++            tmp_int = perms[p]
++            perms[p] = perms[inds[p]]
++            perms[inds[p]] = tmp_int
++    tmp_int = n - krank
++    # SIDE,UPLO,TRANSA,DIAG,M,N,ALPHA,A,LDA,B,LDB
++    ztrsm('R', 'L', 'N', 'N',
++          &tmp_int, &krank, &one, &a[0, 0], &n, &a[0, krank], &n)
++
++    return perms, a[:krank, krank:]
++
++
++def idzr_qrpiv(cnp.ndarray[cnp.complex128_t, mode="c", ndim=2] a, int krank):
++    cdef int m = a.shape[0], n = a.shape[1]
++    cdef int loop = 0, loops, kpiv = 0, i = 0, tmp_int = 0
++    cdef cnp.ndarray col_norms = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
++    cdef double complex tmp_sca = 0.
++    cdef cnp.ndarray taus = cnp.PyArray_ZEROS(1, [m], cnp.NPY_COMPLEX128, 0)
++    cdef cnp.ndarray ind = cnp.PyArray_ZEROS(1, [n], cnp.NPY_INT64, 0)
++    cdef double complex[::1] taus_v = taus
++    cdef cnp.float64_t feps = 0.1e-16  # Smaller than np.finfo(np.float64).eps
++    cdef cnp.float64_t ssmax, ssmaxin
++    cdef int nupdate = 0
++
++    loops = min(krank, min(m, n))
++    for i in range(n):
++        col_norms[i] = dznrm2(&m, &a[0, i], &n)**2
++
++    kpiv = np.argmax(col_norms)
++    ssmax = col_norms[kpiv]
++    ssmaxin = ssmax
++
++    for loop in range(loops):
++
++        ind[loop] = kpiv
++        # Swap columns a[:, k] and a[:, kpiv]
++        a[:, [kpiv, loop]] = a[:, [loop, kpiv]]
++        # Swap col_norms[krank] and col_norms[kpiv]
++        col_norms[[kpiv, loop]] = col_norms[[loop, kpiv]]
++
++        if loop < m-1:
++            tmp_sca = a[loop, loop]
++            # FIX: Convert these to F_INT
++            tmp_int = (m - loop)
++            zlarfgp(&tmp_int, &tmp_sca, &a[loop+1, loop], &n, &taus_v[loop])
++
++            # Overwrite with 1. for easy matmul
++            a[loop, loop] = 1
++            if loop < n-1:
++                # Apply the householder reflector to the rest on the right
++                a[loop:, loop+1:] -= np.outer(
++                    np.conj(taus[loop])*a[loop:, loop],
++                    a[loop:, loop].conj() @ a[loop:, loop+1:]
++                    )
++            # Put back the beta in place
++            a[loop, loop] = tmp_sca
++
++            # Update the norms
++            col_norms[loop] = 0
++            col_norms[loop+1:] -= (a[loop, loop+1:]*a[loop, loop+1:].conj()).real
++            ssmax = 0
++            kpiv = loop+1
++
++            if loop < n-1:
++                kpiv = np.argmax(col_norms[loop+1:]) + (loop + 1)
++                ssmax = col_norms[kpiv]
++            if (((ssmax < 1000*feps*ssmaxin) and (nupdate == 0)) or
++                    ((ssmax < ((1000*feps)**2)*ssmaxin) and (nupdate == 1))):
++                nupdate += 1
++                ssmax = 0
++                kpiv = loop+1
++
++                if loop < n-1:
++                    for i in range(loop+1, n):
++                        tmp_int = m-loop-1
++                        col_norms[i] = dznrm2(&tmp_int, &a[loop+1, i], &n)**2
++                    kpiv = np.argmax(col_norms[loop+1:]) + (loop + 1)
++                    ssmax = col_norms[kpiv]
++
++    return ind, taus
++
++
++def idzr_rid(A: LinearOperator, int krank, rng=None):
++    cdef int m = A.shape[0], n = A.shape[1], k = 0
++    cdef int L = min(krank+2, min(m, n))
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] r
++
++    if not rng:
++        rng = np.random.default_rng()
++
++    r = cnp.PyArray_EMPTY(2, [L, n], cnp.NPY_COMPLEX128, 0)
++    for k in range(L):
++        r[k, :] = A.rmatvec(rng.uniform(size=(m,2)).view(np.complex128).ravel())
++
++    return idzr_id(a=r.conj(), krank=krank)
++
++
++def idzr_rsvd(A: LinearOperator, int krank, rng=None):
++    cdef int n = A.shape[1], j
++    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms
++    cdef cnp.ndarray[cnp.complex128_t, ndim=2] proj
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] col
++
++    perms, proj = idzr_rid(A, krank, rng)
++    # idd_getcols
++    col = cnp.PyArray_EMPTY(2, [n, krank], cnp.NPY_COMPLEX128, 0)
++    x = cnp.PyArray_ZEROS(1, [n], cnp.NPY_COMPLEX128, 0)
++    for j in range(krank):
++        x[perms[j]] = 1.
++        col[:, j] = A.matvec(x)
++        x[perms[j]] = 0.
++
++    return idz_id2svd(cols=col, perms=perms, proj=proj)
++
++
++def idzr_svd(cnp.ndarray[cnp.complex128_t, mode="c", ndim=2] a, int krank):
++    cdef int m = a.shape[0], n = a.shape[1], info = 0
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] taus
++    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] inds
++    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] UU
++    cdef cnp.ndarray[cnp.complex128_t, mode='fortran', ndim=2] C
++    UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_COMPLEX128, 0)
++
++    krank = min(krank, min(m, n))
++    # Get the pivoted QR
++    inds, taus = idzr_qrpiv(a, krank)
++    r = np.triu(a[:krank, :])
++    # Apply pivots in reverse
++    for p in range(krank-1, -1, -1):
++        r[:, [p, inds[p]]] = r[:, [inds[p], p]]
++
++    # JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO
++    # zgesvd()
++    UU[:krank, :krank], S, V = la.svd(r, full_matrices=False)
++
++    # Apply Q to U via zunm2r
++    np.conjugate(taus, out=taus)
++    # But do the adjoint dance for LAPACK via U.H @ Q.H; use a for scratch
++    C = a[:, :krank].conj().copy(order='F')
++    zunm2r('R', 'C',
++           &krank, &m, &krank, &C[0, 0], &m, &taus[0],
++           &UU[0,0], &krank, &a[0, 0], &info)
++
++    return UU, S, V
+diff --git a/scipy/linalg/_interpolative_backend.py b/scipy/linalg/_interpolative_backend.py
+deleted file mode 100644
+index 7835314f7..000000000
+--- a/scipy/linalg/_interpolative_backend.py
++++ /dev/null
+@@ -1,1681 +0,0 @@
+-#******************************************************************************
+-#   Copyright (C) 2013 Kenneth L. Ho
+-#
+-#   Redistribution and use in source and binary forms, with or without
+-#   modification, are permitted provided that the following conditions are met:
+-#
+-#   Redistributions of source code must retain the above copyright notice, this
+-#   list of conditions and the following disclaimer. Redistributions in binary
+-#   form must reproduce the above copyright notice, this list of conditions and
+-#   the following disclaimer in the documentation and/or other materials
+-#   provided with the distribution.
+-#
+-#   None of the names of the copyright holders may be used to endorse or
+-#   promote products derived from this software without specific prior written
+-#   permission.
+-#
+-#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+-#   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+-#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+-#   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+-#   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+-#   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+-#   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+-#   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+-#   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+-#   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+-#   POSSIBILITY OF SUCH DAMAGE.
+-#******************************************************************************
+-
+-"""
+-Direct wrappers for Fortran `id_dist` backend.
+-"""
+-
+-import scipy.linalg._interpolative as _id
+-import numpy as np
+-
+-_RETCODE_ERROR = RuntimeError("nonzero return code")
+-
+-
+-def _asfortranarray_copy(A):
+-    """
+-    Same as np.asfortranarray, but ensure a copy
+-    """
+-    A = np.asarray(A)
+-    if A.flags.f_contiguous:
+-        A = A.copy(order="F")
+-    else:
+-        A = np.asfortranarray(A)
+-    return A
+-
+-
+-#------------------------------------------------------------------------------
+-# id_rand.f
+-#------------------------------------------------------------------------------
+-
+-def id_srand(n):
+-    """
+-    Generate standard uniform pseudorandom numbers via a very efficient lagged
+-    Fibonacci method.
+-
+-    :param n:
+-        Number of pseudorandom numbers to generate.
+-    :type n: int
+-
+-    :return:
+-        Pseudorandom numbers.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.id_srand(n)
+-
+-
+-def id_srandi(t):
+-    """
+-    Initialize seed values for :func:`id_srand` (any appropriately random
+-    numbers will do).
+-
+-    :param t:
+-        Array of 55 seed values.
+-    :type t: :class:`numpy.ndarray`
+-    """
+-    t = np.asfortranarray(t)
+-    _id.id_srandi(t)
+-
+-
+-def id_srando():
+-    """
+-    Reset seed values to their original values.
+-    """
+-    _id.id_srando()
+-
+-
+-#------------------------------------------------------------------------------
+-# idd_frm.f
+-#------------------------------------------------------------------------------
+-
+-def idd_frm(n, w, x):
+-    """
+-    Transform real vector via a composition of Rokhlin's random transform,
+-    random subselection, and an FFT.
+-
+-    In contrast to :func:`idd_sfrm`, this routine works best when the length of
+-    the transformed vector is the power-of-two integer output by
+-    :func:`idd_frmi`, or when the length is not specified but instead
+-    determined a posteriori from the output. The returned transformed vector is
+-    randomly permuted.
+-
+-    :param n:
+-        Greatest power-of-two integer satisfying `n <= x.size` as obtained from
+-        :func:`idd_frmi`; `n` is also the length of the output vector.
+-    :type n: int
+-    :param w:
+-        Initialization array constructed by :func:`idd_frmi`.
+-    :type w: :class:`numpy.ndarray`
+-    :param x:
+-        Vector to be transformed.
+-    :type x: :class:`numpy.ndarray`
+-
+-    :return:
+-        Transformed vector.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idd_frm(n, w, x)
+-
+-
+-def idd_sfrm(l, n, w, x):
+-    """
+-    Transform real vector via a composition of Rokhlin's random transform,
+-    random subselection, and an FFT.
+-
+-    In contrast to :func:`idd_frm`, this routine works best when the length of
+-    the transformed vector is known a priori.
+-
+-    :param l:
+-        Length of transformed vector, satisfying `l <= n`.
+-    :type l: int
+-    :param n:
+-        Greatest power-of-two integer satisfying `n <= x.size` as obtained from
+-        :func:`idd_sfrmi`.
+-    :type n: int
+-    :param w:
+-        Initialization array constructed by :func:`idd_sfrmi`.
+-    :type w: :class:`numpy.ndarray`
+-    :param x:
+-        Vector to be transformed.
+-    :type x: :class:`numpy.ndarray`
+-
+-    :return:
+-        Transformed vector.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idd_sfrm(l, n, w, x)
+-
+-
+-def idd_frmi(m):
+-    """
+-    Initialize data for :func:`idd_frm`.
+-
+-    :param m:
+-        Length of vector to be transformed.
+-    :type m: int
+-
+-    :return:
+-        Greatest power-of-two integer `n` satisfying `n <= m`.
+-    :rtype: int
+-    :return:
+-        Initialization array to be used by :func:`idd_frm`.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idd_frmi(m)
+-
+-
+-def idd_sfrmi(l, m):
+-    """
+-    Initialize data for :func:`idd_sfrm`.
+-
+-    :param l:
+-        Length of output transformed vector.
+-    :type l: int
+-    :param m:
+-        Length of the vector to be transformed.
+-    :type m: int
+-
+-    :return:
+-        Greatest power-of-two integer `n` satisfying `n <= m`.
+-    :rtype: int
+-    :return:
+-        Initialization array to be used by :func:`idd_sfrm`.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idd_sfrmi(l, m)
+-
+-
+-#------------------------------------------------------------------------------
+-# idd_id.f
+-#------------------------------------------------------------------------------
+-
+-def iddp_id(eps, A):
+-    """
+-    Compute ID of a real matrix to a specified relative precision.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-
+-    :return:
+-        Rank of ID.
+-    :rtype: int
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = _asfortranarray_copy(A)
+-    k, idx, rnorms = _id.iddp_id(eps, A)
+-    n = A.shape[1]
+-    proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
+-    return k, idx, proj
+-
+-
+-def iddr_id(A, k):
+-    """
+-    Compute ID of a real matrix to a specified rank.
+-
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-    :param k:
+-        Rank of ID.
+-    :type k: int
+-
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = _asfortranarray_copy(A)
+-    idx, rnorms = _id.iddr_id(A, k)
+-    n = A.shape[1]
+-    proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
+-    return idx, proj
+-
+-
+-def idd_reconid(B, idx, proj):
+-    """
+-    Reconstruct matrix from real ID.
+-
+-    :param B:
+-        Skeleton matrix.
+-    :type B: :class:`numpy.ndarray`
+-    :param idx:
+-        Column index array.
+-    :type idx: :class:`numpy.ndarray`
+-    :param proj:
+-        Interpolation coefficients.
+-    :type proj: :class:`numpy.ndarray`
+-
+-    :return:
+-        Reconstructed matrix.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    B = np.asfortranarray(B)
+-    if proj.size > 0:
+-        return _id.idd_reconid(B, idx, proj)
+-    else:
+-        return B[:, np.argsort(idx)]
+-
+-
+-def idd_reconint(idx, proj):
+-    """
+-    Reconstruct interpolation matrix from real ID.
+-
+-    :param idx:
+-        Column index array.
+-    :type idx: :class:`numpy.ndarray`
+-    :param proj:
+-        Interpolation coefficients.
+-    :type proj: :class:`numpy.ndarray`
+-
+-    :return:
+-        Interpolation matrix.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idd_reconint(idx, proj)
+-
+-
+-def idd_copycols(A, k, idx):
+-    """
+-    Reconstruct skeleton matrix from real ID.
+-
+-    :param A:
+-        Original matrix.
+-    :type A: :class:`numpy.ndarray`
+-    :param k:
+-        Rank of ID.
+-    :type k: int
+-    :param idx:
+-        Column index array.
+-    :type idx: :class:`numpy.ndarray`
+-
+-    :return:
+-        Skeleton matrix.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    return _id.idd_copycols(A, k, idx)
+-
+-
+-#------------------------------------------------------------------------------
+-# idd_id2svd.f
+-#------------------------------------------------------------------------------
+-
+-def idd_id2svd(B, idx, proj):
+-    """
+-    Convert real ID to SVD.
+-
+-    :param B:
+-        Skeleton matrix.
+-    :type B: :class:`numpy.ndarray`
+-    :param idx:
+-        Column index array.
+-    :type idx: :class:`numpy.ndarray`
+-    :param proj:
+-        Interpolation coefficients.
+-    :type proj: :class:`numpy.ndarray`
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    B = np.asfortranarray(B)
+-    U, V, S, ier = _id.idd_id2svd(B, idx, proj)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# idd_snorm.f
+-#------------------------------------------------------------------------------
+-
+-def idd_snorm(m, n, matvect, matvec, its=20):
+-    """
+-    Estimate spectral norm of a real matrix by the randomized power method.
+-
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matvect:
+-        Function to apply the matrix transpose to a vector, with call signature
+-        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvect: function
+-    :param matvec:
+-        Function to apply the matrix to a vector, with call signature
+-        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvec: function
+-    :param its:
+-        Number of power method iterations.
+-    :type its: int
+-
+-    :return:
+-        Spectral norm estimate.
+-    :rtype: float
+-    """
+-    snorm, v = _id.idd_snorm(m, n, matvect, matvec, its)
+-    return snorm
+-
+-
+-def idd_diffsnorm(m, n, matvect, matvect2, matvec, matvec2, its=20):
+-    """
+-    Estimate spectral norm of the difference of two real matrices by the
+-    randomized power method.
+-
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matvect:
+-        Function to apply the transpose of the first matrix to a vector, with
+-        call signature `y = matvect(x)`, where `x` and `y` are the input and
+-        output vectors, respectively.
+-    :type matvect: function
+-    :param matvect2:
+-        Function to apply the transpose of the second matrix to a vector, with
+-        call signature `y = matvect2(x)`, where `x` and `y` are the input and
+-        output vectors, respectively.
+-    :type matvect2: function
+-    :param matvec:
+-        Function to apply the first matrix to a vector, with call signature
+-        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvec: function
+-    :param matvec2:
+-        Function to apply the second matrix to a vector, with call signature
+-        `y = matvec2(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvec2: function
+-    :param its:
+-        Number of power method iterations.
+-    :type its: int
+-
+-    :return:
+-        Spectral norm estimate of matrix difference.
+-    :rtype: float
+-    """
+-    return _id.idd_diffsnorm(m, n, matvect, matvect2, matvec, matvec2, its)
+-
+-
+-#------------------------------------------------------------------------------
+-# idd_svd.f
+-#------------------------------------------------------------------------------
+-
+-def iddr_svd(A, k):
+-    """
+-    Compute SVD of a real matrix to a specified rank.
+-
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-    :param k:
+-        Rank of SVD.
+-    :type k: int
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    U, V, S, ier = _id.iddr_svd(A, k)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    return U, V, S
+-
+-
+-def iddp_svd(eps, A):
+-    """
+-    Compute SVD of a real matrix to a specified relative precision.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    k, iU, iV, iS, w, ier = _id.iddp_svd(eps, A)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
+-    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
+-    S = w[iS-1:iS+k-1]
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# iddp_aid.f
+-#------------------------------------------------------------------------------
+-
+-def iddp_aid(eps, A):
+-    """
+-    Compute ID of a real matrix to a specified relative precision using random
+-    sampling.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-
+-    :return:
+-        Rank of ID.
+-    :rtype: int
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    n2, w = idd_frmi(m)
+-    proj = np.empty(n*(2*n2 + 1) + n2 + 1, order='F')
+-    k, idx, proj = _id.iddp_aid(eps, A, w, proj)
+-    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
+-    return k, idx, proj
+-
+-
+-def idd_estrank(eps, A):
+-    """
+-    Estimate rank of a real matrix to a specified relative precision using
+-    random sampling.
+-
+-    The output rank is typically about 8 higher than the actual rank.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-
+-    :return:
+-        Rank estimate.
+-    :rtype: int
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    n2, w = idd_frmi(m)
+-    ra = np.empty(n*n2 + (n + 1)*(n2 + 1), order='F')
+-    k, ra = _id.idd_estrank(eps, A, w, ra)
+-    return k
+-
+-
+-#------------------------------------------------------------------------------
+-# iddp_asvd.f
+-#------------------------------------------------------------------------------
+-
+-def iddp_asvd(eps, A):
+-    """
+-    Compute SVD of a real matrix to a specified relative precision using random
+-    sampling.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    n2, winit = _id.idd_frmi(m)
+-    w = np.empty(
+-        max((min(m, n) + 1)*(3*m + 5*n + 1) + 25*min(m, n)**2,
+-            (2*n + 1)*(n2 + 1)),
+-        order='F')
+-    k, iU, iV, iS, w, ier = _id.iddp_asvd(eps, A, winit, w)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
+-    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
+-    S = w[iS-1:iS+k-1]
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# iddp_rid.f
+-#------------------------------------------------------------------------------
+-
+-def iddp_rid(eps, m, n, matvect):
+-    """
+-    Compute ID of a real matrix to a specified relative precision using random
+-    matrix-vector multiplication.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matvect:
+-        Function to apply the matrix transpose to a vector, with call signature
+-        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvect: function
+-
+-    :return:
+-        Rank of ID.
+-    :rtype: int
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    proj = np.empty(m + 1 + 2*n*(min(m, n) + 1), order='F')
+-    k, idx, proj, ier = _id.iddp_rid(eps, m, n, matvect, proj)
+-    if ier != 0:
+-        raise _RETCODE_ERROR
+-    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
+-    return k, idx, proj
+-
+-
+-def idd_findrank(eps, m, n, matvect):
+-    """
+-    Estimate rank of a real matrix to a specified relative precision using
+-    random matrix-vector multiplication.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matvect:
+-        Function to apply the matrix transpose to a vector, with call signature
+-        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvect: function
+-
+-    :return:
+-        Rank estimate.
+-    :rtype: int
+-    """
+-    k, ra, ier = _id.idd_findrank(eps, m, n, matvect)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    return k
+-
+-
+-#------------------------------------------------------------------------------
+-# iddp_rsvd.f
+-#------------------------------------------------------------------------------
+-
+-def iddp_rsvd(eps, m, n, matvect, matvec):
+-    """
+-    Compute SVD of a real matrix to a specified relative precision using random
+-    matrix-vector multiplication.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matvect:
+-        Function to apply the matrix transpose to a vector, with call signature
+-        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvect: function
+-    :param matvec:
+-        Function to apply the matrix to a vector, with call signature
+-        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvec: function
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    k, iU, iV, iS, w, ier = _id.iddp_rsvd(eps, m, n, matvect, matvec)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
+-    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
+-    S = w[iS-1:iS+k-1]
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# iddr_aid.f
+-#------------------------------------------------------------------------------
+-
+-def iddr_aid(A, k):
+-    """
+-    Compute ID of a real matrix to a specified rank using random sampling.
+-
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-    :param k:
+-        Rank of ID.
+-    :type k: int
+-
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    w = iddr_aidi(m, n, k)
+-    idx, proj = _id.iddr_aid(A, k, w)
+-    if k == n:
+-        proj = np.empty((k, n-k), dtype='float64', order='F')
+-    else:
+-        proj = proj.reshape((k, n-k), order='F')
+-    return idx, proj
+-
+-
+-def iddr_aidi(m, n, k):
+-    """
+-    Initialize array for :func:`iddr_aid`.
+-
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param k:
+-        Rank of ID.
+-    :type k: int
+-
+-    :return:
+-        Initialization array to be used by :func:`iddr_aid`.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.iddr_aidi(m, n, k)
+-
+-
+-#------------------------------------------------------------------------------
+-# iddr_asvd.f
+-#------------------------------------------------------------------------------
+-
+-def iddr_asvd(A, k):
+-    """
+-    Compute SVD of a real matrix to a specified rank using random sampling.
+-
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-    :param k:
+-        Rank of SVD.
+-    :type k: int
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    w = np.empty((2*k + 28)*m + (6*k + 21)*n + 25*k**2 + 100, order='F')
+-    w_ = iddr_aidi(m, n, k)
+-    w[:w_.size] = w_
+-    U, V, S, ier = _id.iddr_asvd(A, k, w)
+-    if ier != 0:
+-        raise _RETCODE_ERROR
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# iddr_rid.f
+-#------------------------------------------------------------------------------
+-
+-def iddr_rid(m, n, matvect, k):
+-    """
+-    Compute ID of a real matrix to a specified rank using random matrix-vector
+-    multiplication.
+-
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matvect:
+-        Function to apply the matrix transpose to a vector, with call signature
+-        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvect: function
+-    :param k:
+-        Rank of ID.
+-    :type k: int
+-
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    idx, proj = _id.iddr_rid(m, n, matvect, k)
+-    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
+-    return idx, proj
+-
+-
+-#------------------------------------------------------------------------------
+-# iddr_rsvd.f
+-#------------------------------------------------------------------------------
+-
+-def iddr_rsvd(m, n, matvect, matvec, k):
+-    """
+-    Compute SVD of a real matrix to a specified rank using random matrix-vector
+-    multiplication.
+-
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matvect:
+-        Function to apply the matrix transpose to a vector, with call signature
+-        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvect: function
+-    :param matvec:
+-        Function to apply the matrix to a vector, with call signature
+-        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvec: function
+-    :param k:
+-        Rank of SVD.
+-    :type k: int
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    U, V, S, ier = _id.iddr_rsvd(m, n, matvect, matvec, k)
+-    if ier != 0:
+-        raise _RETCODE_ERROR
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# idz_frm.f
+-#------------------------------------------------------------------------------
+-
+-def idz_frm(n, w, x):
+-    """
+-    Transform complex vector via a composition of Rokhlin's random transform,
+-    random subselection, and an FFT.
+-
+-    In contrast to :func:`idz_sfrm`, this routine works best when the length of
+-    the transformed vector is the power-of-two integer output by
+-    :func:`idz_frmi`, or when the length is not specified but instead
+-    determined a posteriori from the output. The returned transformed vector is
+-    randomly permuted.
+-
+-    :param n:
+-        Greatest power-of-two integer satisfying `n <= x.size` as obtained from
+-        :func:`idz_frmi`; `n` is also the length of the output vector.
+-    :type n: int
+-    :param w:
+-        Initialization array constructed by :func:`idz_frmi`.
+-    :type w: :class:`numpy.ndarray`
+-    :param x:
+-        Vector to be transformed.
+-    :type x: :class:`numpy.ndarray`
+-
+-    :return:
+-        Transformed vector.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idz_frm(n, w, x)
+-
+-
+-def idz_sfrm(l, n, w, x):
+-    """
+-    Transform complex vector via a composition of Rokhlin's random transform,
+-    random subselection, and an FFT.
+-
+-    In contrast to :func:`idz_frm`, this routine works best when the length of
+-    the transformed vector is known a priori.
+-
+-    :param l:
+-        Length of transformed vector, satisfying `l <= n`.
+-    :type l: int
+-    :param n:
+-        Greatest power-of-two integer satisfying `n <= x.size` as obtained from
+-        :func:`idz_sfrmi`.
+-    :type n: int
+-    :param w:
+-        Initialization array constructed by :func:`idd_sfrmi`.
+-    :type w: :class:`numpy.ndarray`
+-    :param x:
+-        Vector to be transformed.
+-    :type x: :class:`numpy.ndarray`
+-
+-    :return:
+-        Transformed vector.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idz_sfrm(l, n, w, x)
+-
+-
+-def idz_frmi(m):
+-    """
+-    Initialize data for :func:`idz_frm`.
+-
+-    :param m:
+-        Length of vector to be transformed.
+-    :type m: int
+-
+-    :return:
+-        Greatest power-of-two integer `n` satisfying `n <= m`.
+-    :rtype: int
+-    :return:
+-        Initialization array to be used by :func:`idz_frm`.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idz_frmi(m)
+-
+-
+-def idz_sfrmi(l, m):
+-    """
+-    Initialize data for :func:`idz_sfrm`.
+-
+-    :param l:
+-        Length of output transformed vector.
+-    :type l: int
+-    :param m:
+-        Length of the vector to be transformed.
+-    :type m: int
+-
+-    :return:
+-        Greatest power-of-two integer `n` satisfying `n <= m`.
+-    :rtype: int
+-    :return:
+-        Initialization array to be used by :func:`idz_sfrm`.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idz_sfrmi(l, m)
+-
+-
+-#------------------------------------------------------------------------------
+-# idz_id.f
+-#------------------------------------------------------------------------------
+-
+-def idzp_id(eps, A):
+-    """
+-    Compute ID of a complex matrix to a specified relative precision.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-
+-    :return:
+-        Rank of ID.
+-    :rtype: int
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = _asfortranarray_copy(A)
+-    k, idx, rnorms = _id.idzp_id(eps, A)
+-    n = A.shape[1]
+-    proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
+-    return k, idx, proj
+-
+-
+-def idzr_id(A, k):
+-    """
+-    Compute ID of a complex matrix to a specified rank.
+-
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-    :param k:
+-        Rank of ID.
+-    :type k: int
+-
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = _asfortranarray_copy(A)
+-    idx, rnorms = _id.idzr_id(A, k)
+-    n = A.shape[1]
+-    proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
+-    return idx, proj
+-
+-
+-def idz_reconid(B, idx, proj):
+-    """
+-    Reconstruct matrix from complex ID.
+-
+-    :param B:
+-        Skeleton matrix.
+-    :type B: :class:`numpy.ndarray`
+-    :param idx:
+-        Column index array.
+-    :type idx: :class:`numpy.ndarray`
+-    :param proj:
+-        Interpolation coefficients.
+-    :type proj: :class:`numpy.ndarray`
+-
+-    :return:
+-        Reconstructed matrix.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    B = np.asfortranarray(B)
+-    if proj.size > 0:
+-        return _id.idz_reconid(B, idx, proj)
+-    else:
+-        return B[:, np.argsort(idx)]
+-
+-
+-def idz_reconint(idx, proj):
+-    """
+-    Reconstruct interpolation matrix from complex ID.
+-
+-    :param idx:
+-        Column index array.
+-    :type idx: :class:`numpy.ndarray`
+-    :param proj:
+-        Interpolation coefficients.
+-    :type proj: :class:`numpy.ndarray`
+-
+-    :return:
+-        Interpolation matrix.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idz_reconint(idx, proj)
+-
+-
+-def idz_copycols(A, k, idx):
+-    """
+-    Reconstruct skeleton matrix from complex ID.
+-
+-    :param A:
+-        Original matrix.
+-    :type A: :class:`numpy.ndarray`
+-    :param k:
+-        Rank of ID.
+-    :type k: int
+-    :param idx:
+-        Column index array.
+-    :type idx: :class:`numpy.ndarray`
+-
+-    :return:
+-        Skeleton matrix.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    return _id.idz_copycols(A, k, idx)
+-
+-
+-#------------------------------------------------------------------------------
+-# idz_id2svd.f
+-#------------------------------------------------------------------------------
+-
+-def idz_id2svd(B, idx, proj):
+-    """
+-    Convert complex ID to SVD.
+-
+-    :param B:
+-        Skeleton matrix.
+-    :type B: :class:`numpy.ndarray`
+-    :param idx:
+-        Column index array.
+-    :type idx: :class:`numpy.ndarray`
+-    :param proj:
+-        Interpolation coefficients.
+-    :type proj: :class:`numpy.ndarray`
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    B = np.asfortranarray(B)
+-    U, V, S, ier = _id.idz_id2svd(B, idx, proj)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# idz_snorm.f
+-#------------------------------------------------------------------------------
+-
+-def idz_snorm(m, n, matveca, matvec, its=20):
+-    """
+-    Estimate spectral norm of a complex matrix by the randomized power method.
+-
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matveca:
+-        Function to apply the matrix adjoint to a vector, with call signature
+-        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matveca: function
+-    :param matvec:
+-        Function to apply the matrix to a vector, with call signature
+-        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvec: function
+-    :param its:
+-        Number of power method iterations.
+-    :type its: int
+-
+-    :return:
+-        Spectral norm estimate.
+-    :rtype: float
+-    """
+-    snorm, v = _id.idz_snorm(m, n, matveca, matvec, its)
+-    return snorm
+-
+-
+-def idz_diffsnorm(m, n, matveca, matveca2, matvec, matvec2, its=20):
+-    """
+-    Estimate spectral norm of the difference of two complex matrices by the
+-    randomized power method.
+-
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matveca:
+-        Function to apply the adjoint of the first matrix to a vector, with
+-        call signature `y = matveca(x)`, where `x` and `y` are the input and
+-        output vectors, respectively.
+-    :type matveca: function
+-    :param matveca2:
+-        Function to apply the adjoint of the second matrix to a vector, with
+-        call signature `y = matveca2(x)`, where `x` and `y` are the input and
+-        output vectors, respectively.
+-    :type matveca2: function
+-    :param matvec:
+-        Function to apply the first matrix to a vector, with call signature
+-        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvec: function
+-    :param matvec2:
+-        Function to apply the second matrix to a vector, with call signature
+-        `y = matvec2(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvec2: function
+-    :param its:
+-        Number of power method iterations.
+-    :type its: int
+-
+-    :return:
+-        Spectral norm estimate of matrix difference.
+-    :rtype: float
+-    """
+-    return _id.idz_diffsnorm(m, n, matveca, matveca2, matvec, matvec2, its)
+-
+-
+-#------------------------------------------------------------------------------
+-# idz_svd.f
+-#------------------------------------------------------------------------------
+-
+-def idzr_svd(A, k):
+-    """
+-    Compute SVD of a complex matrix to a specified rank.
+-
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-    :param k:
+-        Rank of SVD.
+-    :type k: int
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    U, V, S, ier = _id.idzr_svd(A, k)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    return U, V, S
+-
+-
+-def idzp_svd(eps, A):
+-    """
+-    Compute SVD of a complex matrix to a specified relative precision.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    k, iU, iV, iS, w, ier = _id.idzp_svd(eps, A)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
+-    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
+-    S = w[iS-1:iS+k-1]
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# idzp_aid.f
+-#------------------------------------------------------------------------------
+-
+-def idzp_aid(eps, A):
+-    """
+-    Compute ID of a complex matrix to a specified relative precision using
+-    random sampling.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-
+-    :return:
+-        Rank of ID.
+-    :rtype: int
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    n2, w = idz_frmi(m)
+-    proj = np.empty(n*(2*n2 + 1) + n2 + 1, dtype='complex128', order='F')
+-    k, idx, proj = _id.idzp_aid(eps, A, w, proj)
+-    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
+-    return k, idx, proj
+-
+-
+-def idz_estrank(eps, A):
+-    """
+-    Estimate rank of a complex matrix to a specified relative precision using
+-    random sampling.
+-
+-    The output rank is typically about 8 higher than the actual rank.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-
+-    :return:
+-        Rank estimate.
+-    :rtype: int
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    n2, w = idz_frmi(m)
+-    ra = np.empty(n*n2 + (n + 1)*(n2 + 1), dtype='complex128', order='F')
+-    k, ra = _id.idz_estrank(eps, A, w, ra)
+-    return k
+-
+-
+-#------------------------------------------------------------------------------
+-# idzp_asvd.f
+-#------------------------------------------------------------------------------
+-
+-def idzp_asvd(eps, A):
+-    """
+-    Compute SVD of a complex matrix to a specified relative precision using
+-    random sampling.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    n2, winit = _id.idz_frmi(m)
+-    w = np.empty(
+-        max((min(m, n) + 1)*(3*m + 5*n + 11) + 8*min(m, n)**2,
+-            (2*n + 1)*(n2 + 1)),
+-        dtype=np.complex128, order='F')
+-    k, iU, iV, iS, w, ier = _id.idzp_asvd(eps, A, winit, w)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
+-    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
+-    S = w[iS-1:iS+k-1]
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# idzp_rid.f
+-#------------------------------------------------------------------------------
+-
+-def idzp_rid(eps, m, n, matveca):
+-    """
+-    Compute ID of a complex matrix to a specified relative precision using
+-    random matrix-vector multiplication.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matveca:
+-        Function to apply the matrix adjoint to a vector, with call signature
+-        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matveca: function
+-
+-    :return:
+-        Rank of ID.
+-    :rtype: int
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    proj = np.empty(
+-        m + 1 + 2*n*(min(m, n) + 1),
+-        dtype=np.complex128, order='F')
+-    k, idx, proj, ier = _id.idzp_rid(eps, m, n, matveca, proj)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
+-    return k, idx, proj
+-
+-
+-def idz_findrank(eps, m, n, matveca):
+-    """
+-    Estimate rank of a complex matrix to a specified relative precision using
+-    random matrix-vector multiplication.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matveca:
+-        Function to apply the matrix adjoint to a vector, with call signature
+-        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matveca: function
+-
+-    :return:
+-        Rank estimate.
+-    :rtype: int
+-    """
+-    k, ra, ier = _id.idz_findrank(eps, m, n, matveca)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    return k
+-
+-
+-#------------------------------------------------------------------------------
+-# idzp_rsvd.f
+-#------------------------------------------------------------------------------
+-
+-def idzp_rsvd(eps, m, n, matveca, matvec):
+-    """
+-    Compute SVD of a complex matrix to a specified relative precision using
+-    random matrix-vector multiplication.
+-
+-    :param eps:
+-        Relative precision.
+-    :type eps: float
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matveca:
+-        Function to apply the matrix adjoint to a vector, with call signature
+-        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matveca: function
+-    :param matvec:
+-        Function to apply the matrix to a vector, with call signature
+-        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvec: function
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    k, iU, iV, iS, w, ier = _id.idzp_rsvd(eps, m, n, matveca, matvec)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
+-    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
+-    S = w[iS-1:iS+k-1]
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# idzr_aid.f
+-#------------------------------------------------------------------------------
+-
+-def idzr_aid(A, k):
+-    """
+-    Compute ID of a complex matrix to a specified rank using random sampling.
+-
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-    :param k:
+-        Rank of ID.
+-    :type k: int
+-
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    w = idzr_aidi(m, n, k)
+-    idx, proj = _id.idzr_aid(A, k, w)
+-    if k == n:
+-        proj = np.empty((k, n-k), dtype='complex128', order='F')
+-    else:
+-        proj = proj.reshape((k, n-k), order='F')
+-    return idx, proj
+-
+-
+-def idzr_aidi(m, n, k):
+-    """
+-    Initialize array for :func:`idzr_aid`.
+-
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param k:
+-        Rank of ID.
+-    :type k: int
+-
+-    :return:
+-        Initialization array to be used by :func:`idzr_aid`.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    return _id.idzr_aidi(m, n, k)
+-
+-
+-#------------------------------------------------------------------------------
+-# idzr_asvd.f
+-#------------------------------------------------------------------------------
+-
+-def idzr_asvd(A, k):
+-    """
+-    Compute SVD of a complex matrix to a specified rank using random sampling.
+-
+-    :param A:
+-        Matrix.
+-    :type A: :class:`numpy.ndarray`
+-    :param k:
+-        Rank of SVD.
+-    :type k: int
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    A = np.asfortranarray(A)
+-    m, n = A.shape
+-    w = np.empty(
+-        (2*k + 22)*m + (6*k + 21)*n + 8*k**2 + 10*k + 90,
+-        dtype='complex128', order='F')
+-    w_ = idzr_aidi(m, n, k)
+-    w[:w_.size] = w_
+-    U, V, S, ier = _id.idzr_asvd(A, k, w)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    return U, V, S
+-
+-
+-#------------------------------------------------------------------------------
+-# idzr_rid.f
+-#------------------------------------------------------------------------------
+-
+-def idzr_rid(m, n, matveca, k):
+-    """
+-    Compute ID of a complex matrix to a specified rank using random
+-    matrix-vector multiplication.
+-
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matveca:
+-        Function to apply the matrix adjoint to a vector, with call signature
+-        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matveca: function
+-    :param k:
+-        Rank of ID.
+-    :type k: int
+-
+-    :return:
+-        Column index array.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Interpolation coefficients.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    idx, proj = _id.idzr_rid(m, n, matveca, k)
+-    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
+-    return idx, proj
+-
+-
+-#------------------------------------------------------------------------------
+-# idzr_rsvd.f
+-#------------------------------------------------------------------------------
+-
+-def idzr_rsvd(m, n, matveca, matvec, k):
+-    """
+-    Compute SVD of a complex matrix to a specified rank using random
+-    matrix-vector multiplication.
+-
+-    :param m:
+-        Matrix row dimension.
+-    :type m: int
+-    :param n:
+-        Matrix column dimension.
+-    :type n: int
+-    :param matveca:
+-        Function to apply the matrix adjoint to a vector, with call signature
+-        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matveca: function
+-    :param matvec:
+-        Function to apply the matrix to a vector, with call signature
+-        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
+-        respectively.
+-    :type matvec: function
+-    :param k:
+-        Rank of SVD.
+-    :type k: int
+-
+-    :return:
+-        Left singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Right singular vectors.
+-    :rtype: :class:`numpy.ndarray`
+-    :return:
+-        Singular values.
+-    :rtype: :class:`numpy.ndarray`
+-    """
+-    U, V, S, ier = _id.idzr_rsvd(m, n, matveca, matvec, k)
+-    if ier:
+-        raise _RETCODE_ERROR
+-    return U, V, S
+diff --git a/scipy/linalg/interpolative.py b/scipy/linalg/interpolative.py
+index b91cdd63a..f946b059f 100644
+--- a/scipy/linalg/interpolative.py
++++ b/scipy/linalg/interpolative.py
+@@ -1,4 +1,4 @@
+-#******************************************************************************
++#  ******************************************************************************
+ #   Copyright (C) 2013 Kenneth L. Ho
+ #
+ #   Redistribution and use in source and binary forms, with or without
+@@ -25,19 +25,19 @@
+ #   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ #   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ #   POSSIBILITY OF SUCH DAMAGE.
+-#******************************************************************************
+-
+-# Python module for interfacing with `id_dist`.
++#  ******************************************************************************
+ 
+ r"""
+ ======================================================================
+ Interpolative matrix decomposition (:mod:`scipy.linalg.interpolative`)
+ ======================================================================
+ 
+-.. moduleauthor:: Kenneth L. Ho 
+-
+ .. versionadded:: 0.13
+ 
++.. versionchanged:: 1.15.0
++    The underlying algorithms have been ported to Python from the original Fortran77
++    code. See references below for more details.
++
+ .. currentmodule:: scipy.linalg.interpolative
+ 
+ An interpolative decomposition (ID) of a matrix :math:`A \in
+@@ -94,7 +94,7 @@ Main functionality:
+    estimate_spectral_norm_diff
+    estimate_rank
+ 
+-Support functions:
++Following support functions are deprecated and will be removed in SciPy 1.17.0:
+ 
+ .. autosummary::
+    :toctree: generated/
+@@ -106,16 +106,13 @@ Support functions:
+ References
+ ==========
+ 
+-This module uses the ID software package [1]_ by Martinsson, Rokhlin,
+-Shkolnisky, and Tygert, which is a Fortran library for computing IDs
+-using various algorithms, including the rank-revealing QR approach of
+-[2]_ and the more recent randomized methods described in [3]_, [4]_,
+-and [5]_. This module exposes its functionality in a way convenient
+-for Python users. Note that this module does not add any functionality
+-beyond that of organizing a simpler and more consistent interface.
++This module uses the algorithms found in ID software package [1]_ by Martinsson,
++Rokhlin, Shkolnisky, and Tygert, which is a Fortran library for computing IDs using
++various algorithms, including the rank-revealing QR approach of [2]_ and the more
++recent randomized methods described in [3]_, [4]_, and [5]_.
+ 
+-We advise the user to consult also the `documentation for the ID package
+-`_.
++We advise the user to consult also the documentation for the `ID package
++`_.
+ 
+ .. [1] P.G. Martinsson, V. Rokhlin, Y. Shkolnisky, M. Tygert. "ID: a
+     software package for low-rank approximation of matrices via interpolative
+@@ -356,25 +353,8 @@ depending on the representation. The parameter ``eps`` controls the definition
+ of the numerical rank.
+ 
+ Finally, the random number generation required for all randomized routines can
+-be controlled via :func:`scipy.linalg.interpolative.seed`. To reset the seed
+-values to their original values, use:
+-
+->>> sli.seed('default')
+-
+-To specify the seed values, use:
+-
+->>> s = 42
+->>> sli.seed(s)
+-
+-where ``s`` must be an integer or array of 55 floats. If an integer, the array
+-of floats is obtained by using ``numpy.random.rand`` with the given integer
+-seed.
+-
+-To simply generate some random numbers, type:
+-
+->>> arr = sli.rand(n)
+-
+-where ``n`` is the number of random numbers to generate.
++be controlled via providing NumPy pseudo-random generators with a fixed seed. See
++:class:`numpy.random.Generator` and :func:`numpy.random.default_rng` for more details.
+ 
+ Remarks
+ -------
+@@ -385,9 +365,9 @@ backend routine.
+ 
+ """
+ 
+-import scipy.linalg._interpolative_backend as _backend
++import scipy.linalg._decomp_interpolative as _backend
+ import numpy as np
+-import sys
++import warnings
+ 
+ __all__ = [
+     'estimate_rank',
+@@ -405,9 +385,18 @@ __all__ = [
+ 
+ _DTYPE_ERROR = ValueError("invalid input dtype (input must be float64 or complex128)")
+ _TYPE_ERROR = TypeError("invalid input type (must be array or LinearOperator)")
+-_32BIT_ERROR = ValueError("interpolative decomposition on 32-bit systems "
+-                          "with complex128 is buggy")
+-_IS_32BIT = (sys.maxsize < 2**32)
++
++
++def _C_contiguous_copy(A):
++    """
++    Same as np.ascontiguousarray, but ensure a copy
++    """
++    A = np.asarray(A)
++    if A.flags.c_contiguous:
++        A = A.copy()
++    else:
++        A = np.ascontiguousarray(A)
++    return A
+ 
+ 
+ def _is_real(A):
+@@ -424,53 +413,29 @@ def _is_real(A):
+ 
+ def seed(seed=None):
+     """
+-    Seed the internal random number generator used in this ID package.
+-
+-    The generator is a lagged Fibonacci method with 55-element internal state.
+-
+-    Parameters
+-    ----------
+-    seed : int, sequence, 'default', optional
+-        If 'default', the random seed is reset to a default value.
+-
+-        If `seed` is a sequence containing 55 floating-point numbers
+-        in range [0,1], these are used to set the internal state of
+-        the generator.
+-
+-        If the value is an integer, the internal state is obtained
+-        from `numpy.random.RandomState` (MT19937) with the integer
+-        used as the initial seed.
+-
+-        If `seed` is omitted (None), ``numpy.random.rand`` is used to
+-        initialize the generator.
++    This function, historically, used to set the seed of the randomization algorithms
++    used in the `scipy.linalg.interpolative` functions written in Fortran77.
+ 
++    The library has been ported to Python and now the functions use the native NumPy
++    generators and this function has no content and returns None. Thus this function
++    should not be used and will be removed in SciPy version 1.17.0.
+     """
+-    # For details, see :func:`_backend.id_srand`, :func:`_backend.id_srandi`,
+-    # and :func:`_backend.id_srando`.
+-
+-    if isinstance(seed, str) and seed == 'default':
+-        _backend.id_srando()
+-    elif hasattr(seed, '__len__'):
+-        state = np.asfortranarray(seed, dtype=float)
+-        if state.shape != (55,):
+-            raise ValueError("invalid input size")
+-        elif state.min() < 0 or state.max() > 1:
+-            raise ValueError("values not in range [0,1]")
+-        _backend.id_srandi(state)
+-    elif seed is None:
+-        _backend.id_srandi(np.random.rand(55))
+-    else:
+-        rnd = np.random.RandomState(seed)
+-        _backend.id_srandi(rnd.rand(55))
++    warnings.warn("`scipy.linalg.interpolative.seed` is deprecated and will be "
++                  "removed in SciPy 1.17.0.", DeprecationWarning, stacklevel=3)
+ 
+ 
+ def rand(*shape):
+     """
+-    Generate standard uniform pseudorandom numbers via a very efficient lagged
+-    Fibonacci method.
++    This function, historically, used to generate uniformly distributed random number
++    for the randomization algorithms used in the `scipy.linalg.interpolative` functions
++    written in Fortran77.
+ 
+-    This routine is used for all random number generation in this package and
+-    can affect ID and SVD results.
++    The library has been ported to Python and now the functions use the native NumPy
++    generators. Thus this function should not be used and will be removed in the
++    SciPy version 1.17.0.
++
++    If pseudo-random numbers are needed, NumPy pseudo-random generators should be used
++    instead.
+ 
+     Parameters
+     ----------
+@@ -478,11 +443,13 @@ def rand(*shape):
+         Shape of output array
+ 
+     """
+-    # For details, see :func:`_backend.id_srand`, and :func:`_backend.id_srando`.
+-    return _backend.id_srand(np.prod(shape)).reshape(shape)
++    warnings.warn("`scipy.linalg.interpolative.rand` is deprecated and will be "
++                  "removed in SciPy 1.17.0.", DeprecationWarning, stacklevel=3)
++    rng = np.random.default_rng()
++    return rng.uniform(low=0., high=1.0, size=shape)
+ 
+ 
+-def interp_decomp(A, eps_or_k, rand=True):
++def interp_decomp(A, eps_or_k, rand=True, rng=None):
+     """
+     Compute ID of a matrix.
+ 
+@@ -546,6 +513,9 @@ def interp_decomp(A, eps_or_k, rand=True):
+         Whether to use random sampling if `A` is of type :class:`numpy.ndarray`
+         (randomized algorithms are always used if `A` is of type
+         :class:`scipy.sparse.linalg.LinearOperator`).
++    rng : :class:`numpy.random.Generator`
++        NumPy generator for the randomization steps in the algorithm. If ``rand`` is
++        ``False``, the argument is ignored.
+ 
+     Returns
+     -------
+@@ -562,57 +532,49 @@ def interp_decomp(A, eps_or_k, rand=True):
+     real = _is_real(A)
+ 
+     if isinstance(A, np.ndarray):
++        A = _C_contiguous_copy(A)
+         if eps_or_k < 1:
+             eps = eps_or_k
+             if rand:
+                 if real:
+-                    k, idx, proj = _backend.iddp_aid(eps, A)
++                    k, idx, proj = _backend.iddp_aid(A, eps, rng=rng)
+                 else:
+-                    if _IS_32BIT:
+-                        raise _32BIT_ERROR
+-                    k, idx, proj = _backend.idzp_aid(eps, A)
++                    k, idx, proj = _backend.idzp_aid(A, eps, rng=rng)
+             else:
+                 if real:
+-                    k, idx, proj = _backend.iddp_id(eps, A)
++                    k, idx, proj = _backend.iddp_id(A, eps)
+                 else:
+-                    k, idx, proj = _backend.idzp_id(eps, A)
+-            return k, idx - 1, proj
++                    k, idx, proj = _backend.idzp_id(A, eps)
++            return k, idx, proj
+         else:
+             k = int(eps_or_k)
+             if rand:
+                 if real:
+-                    idx, proj = _backend.iddr_aid(A, k)
++                    idx, proj = _backend.iddr_aid(A, k, rng=rng)
+                 else:
+-                    if _IS_32BIT:
+-                        raise _32BIT_ERROR
+-                    idx, proj = _backend.idzr_aid(A, k)
++                    idx, proj = _backend.idzr_aid(A, k, rng=rng)
+             else:
+                 if real:
+                     idx, proj = _backend.iddr_id(A, k)
+                 else:
+                     idx, proj = _backend.idzr_id(A, k)
+-            return idx - 1, proj
++            return idx, proj
+     elif isinstance(A, LinearOperator):
+-        m, n = A.shape
+-        matveca = A.rmatvec
++
+         if eps_or_k < 1:
+             eps = eps_or_k
+             if real:
+-                k, idx, proj = _backend.iddp_rid(eps, m, n, matveca)
++                k, idx, proj = _backend.iddp_rid(A, eps, rng=rng)
+             else:
+-                if _IS_32BIT:
+-                    raise _32BIT_ERROR
+-                k, idx, proj = _backend.idzp_rid(eps, m, n, matveca)
+-            return k, idx - 1, proj
++                k, idx, proj = _backend.idzp_rid(A, eps, rng=rng)
++            return k, idx, proj
+         else:
+             k = int(eps_or_k)
+             if real:
+-                idx, proj = _backend.iddr_rid(m, n, matveca, k)
++                idx, proj = _backend.iddr_rid(A, k, rng=rng)
+             else:
+-                if _IS_32BIT:
+-                    raise _32BIT_ERROR
+-                idx, proj = _backend.idzr_rid(m, n, matveca, k)
+-            return idx - 1, proj
++                idx, proj = _backend.idzr_rid(A, k, rng=rng)
++            return idx, proj
+     else:
+         raise _TYPE_ERROR
+ 
+@@ -648,9 +610,9 @@ def reconstruct_matrix_from_id(B, idx, proj):
+         Reconstructed matrix.
+     """
+     if _is_real(B):
+-        return _backend.idd_reconid(B, idx + 1, proj)
++        return _backend.idd_reconid(B, idx, proj)
+     else:
+-        return _backend.idz_reconid(B, idx + 1, proj)
++        return _backend.idz_reconid(B, idx, proj)
+ 
+ 
+ def reconstruct_interp_matrix(idx, proj):
+@@ -662,10 +624,8 @@ def reconstruct_interp_matrix(idx, proj):
+ 
+         P = numpy.hstack([numpy.eye(proj.shape[0]), proj])[:,numpy.argsort(idx)]
+ 
+-    The original matrix can then be reconstructed from its skeleton matrix `B`
+-    via::
+-
+-        numpy.dot(B, P)
++    The original matrix can then be reconstructed from its skeleton matrix ``B``
++    via ``A = B @ P``
+ 
+     See also :func:`reconstruct_matrix_from_id` and
+     :func:`reconstruct_skel_matrix`.
+@@ -677,7 +637,7 @@ def reconstruct_interp_matrix(idx, proj):
+     Parameters
+     ----------
+     idx : :class:`numpy.ndarray`
+-        Column index array.
++        1D column index array.
+     proj : :class:`numpy.ndarray`
+         Interpolation coefficients.
+ 
+@@ -686,10 +646,17 @@ def reconstruct_interp_matrix(idx, proj):
+     :class:`numpy.ndarray`
+         Interpolation matrix.
+     """
++    n, krank = len(idx), proj.shape[0]
+     if _is_real(proj):
+-        return _backend.idd_reconint(idx + 1, proj)
++        p = np.zeros([krank, n], dtype=np.float64)
+     else:
+-        return _backend.idz_reconint(idx + 1, proj)
++        p = np.zeros([krank, n], dtype=np.complex128)
++
++    for ci in range(krank):
++        p[ci, idx[ci]] = 1.0
++    p[:, idx[krank:]] = proj[:, :]
++
++    return p
+ 
+ 
+ def reconstruct_skel_matrix(A, k, idx):
+@@ -726,10 +693,7 @@ def reconstruct_skel_matrix(A, k, idx):
+     :class:`numpy.ndarray`
+         Skeleton matrix.
+     """
+-    if _is_real(A):
+-        return _backend.idd_copycols(A, k, idx + 1)
+-    else:
+-        return _backend.idz_copycols(A, k, idx + 1)
++    return A[:, idx[:k]]
+ 
+ 
+ def id_to_svd(B, idx, proj):
+@@ -753,7 +717,7 @@ def id_to_svd(B, idx, proj):
+     B : :class:`numpy.ndarray`
+         Skeleton matrix.
+     idx : :class:`numpy.ndarray`
+-        Column index array.
++        1D column index array.
+     proj : :class:`numpy.ndarray`
+         Interpolation coefficients.
+ 
+@@ -766,14 +730,16 @@ def id_to_svd(B, idx, proj):
+     V : :class:`numpy.ndarray`
+         Right singular vectors.
+     """
++    B = _C_contiguous_copy(B)
+     if _is_real(B):
+-        U, V, S = _backend.idd_id2svd(B, idx + 1, proj)
++        U, S, V = _backend.idd_id2svd(B, idx, proj)
+     else:
+-        U, V, S = _backend.idz_id2svd(B, idx + 1, proj)
++        U, S, V = _backend.idz_id2svd(B, idx, proj)
++
+     return U, S, V
+ 
+ 
+-def estimate_spectral_norm(A, its=20):
++def estimate_spectral_norm(A, its=20, rng=None):
+     """
+     Estimate spectral norm of a matrix by the randomized power method.
+ 
+@@ -788,6 +754,8 @@ def estimate_spectral_norm(A, its=20):
+         `matvec` and `rmatvec` methods (to apply the matrix and its adjoint).
+     its : int, optional
+         Number of power method iterations.
++    rng : :class:`numpy.random.Generator`
++        NumPy generator for the randomization steps in the algorithm.
+ 
+     Returns
+     -------
+@@ -796,18 +764,14 @@ def estimate_spectral_norm(A, its=20):
+     """
+     from scipy.sparse.linalg import aslinearoperator
+     A = aslinearoperator(A)
+-    m, n = A.shape
+-    def matvec(x):
+-        return A.matvec(x)
+-    def matveca(x):
+-        return A.rmatvec(x)
++
+     if _is_real(A):
+-        return _backend.idd_snorm(m, n, matveca, matvec, its=its)
++        return _backend.idd_snorm(A, its=its, rng=rng)
+     else:
+-        return _backend.idz_snorm(m, n, matveca, matvec, its=its)
++        return _backend.idz_snorm(A, its=its, rng=rng)
+ 
+ 
+-def estimate_spectral_norm_diff(A, B, its=20):
++def estimate_spectral_norm_diff(A, B, its=20, rng=None):
+     """
+     Estimate spectral norm of the difference of two matrices by the randomized
+     power method.
+@@ -826,6 +790,8 @@ def estimate_spectral_norm_diff(A, B, its=20):
+         the `matvec` and `rmatvec` methods (to apply the matrix and its adjoint).
+     its : int, optional
+         Number of power method iterations.
++    rng : :class:`numpy.random.Generator`
++        NumPy generator for the randomization steps in the algorithm.
+ 
+     Returns
+     -------
+@@ -835,30 +801,20 @@ def estimate_spectral_norm_diff(A, B, its=20):
+     from scipy.sparse.linalg import aslinearoperator
+     A = aslinearoperator(A)
+     B = aslinearoperator(B)
+-    m, n = A.shape
+-    def matvec1(x):
+-        return A.matvec(x)
+-    def matveca1(x):
+-        return A.rmatvec(x)
+-    def matvec2(x):
+-        return B.matvec(x)
+-    def matveca2(x):
+-        return B.rmatvec(x)
++
+     if _is_real(A):
+-        return _backend.idd_diffsnorm(
+-            m, n, matveca1, matveca2, matvec1, matvec2, its=its)
++        return _backend.idd_diffsnorm(A, B, its=its, rng=rng)
+     else:
+-        return _backend.idz_diffsnorm(
+-            m, n, matveca1, matveca2, matvec1, matvec2, its=its)
++        return _backend.idz_diffsnorm(A, B, its=its, rng=rng)
+ 
+ 
+-def svd(A, eps_or_k, rand=True):
++def svd(A, eps_or_k, rand=True, rng=None):
+     """
+     Compute SVD of a matrix via an ID.
+ 
+     An SVD of a matrix `A` is a factorization::
+ 
+-        A = numpy.dot(U, numpy.dot(numpy.diag(S), V.conj().T))
++        A = U @ np.diag(S) @ V.conj().T
+ 
+     where `U` and `V` have orthonormal columns and `S` is nonnegative.
+ 
+@@ -889,35 +845,39 @@ def svd(A, eps_or_k, rand=True):
+         Whether to use random sampling if `A` is of type :class:`numpy.ndarray`
+         (randomized algorithms are always used if `A` is of type
+         :class:`scipy.sparse.linalg.LinearOperator`).
++    rng : :class:`numpy.random.Generator`
++        NumPy generator for the randomization steps in the algorithm. If ``rand`` is
++        ``False``, the argument is ignored.
+ 
+     Returns
+     -------
+     U : :class:`numpy.ndarray`
+-        Left singular vectors.
++        2D array of left singular vectors.
+     S : :class:`numpy.ndarray`
+-        Singular values.
++        1D array of singular values.
+     V : :class:`numpy.ndarray`
+-        Right singular vectors.
++        2D array right singular vectors.
+     """
+     from scipy.sparse.linalg import LinearOperator
+ 
+     real = _is_real(A)
+ 
+     if isinstance(A, np.ndarray):
++        A = _C_contiguous_copy(A)
+         if eps_or_k < 1:
+             eps = eps_or_k
+             if rand:
+                 if real:
+-                    U, V, S = _backend.iddp_asvd(eps, A)
++                    U, S, V = _backend.iddp_asvd(A, eps, rng=rng)
+                 else:
+-                    if _IS_32BIT:
+-                        raise _32BIT_ERROR
+-                    U, V, S = _backend.idzp_asvd(eps, A)
++                    U, S, V = _backend.idzp_asvd(A, eps, rng=rng)
+             else:
+                 if real:
+-                    U, V, S = _backend.iddp_svd(eps, A)
++                    U, S, V = _backend.iddp_svd(A, eps)
++                    V = V.T.conj()
+                 else:
+-                    U, V, S = _backend.idzp_svd(eps, A)
++                    U, S, V = _backend.idzp_svd(A, eps)
++                    V = V.T.conj()
+         else:
+             k = int(eps_or_k)
+             if k > min(A.shape):
+@@ -925,44 +885,35 @@ def svd(A, eps_or_k, rand=True):
+                                  f" {min(A.shape)} ")
+             if rand:
+                 if real:
+-                    U, V, S = _backend.iddr_asvd(A, k)
++                    U, S, V = _backend.iddr_asvd(A, k, rng=rng)
+                 else:
+-                    if _IS_32BIT:
+-                        raise _32BIT_ERROR
+-                    U, V, S = _backend.idzr_asvd(A, k)
++                    U, S, V = _backend.idzr_asvd(A, k, rng=rng)
+             else:
+                 if real:
+-                    U, V, S = _backend.iddr_svd(A, k)
++                    U, S, V = _backend.iddr_svd(A, k)
++                    V = V.T.conj()
+                 else:
+-                    U, V, S = _backend.idzr_svd(A, k)
++                    U, S, V = _backend.idzr_svd(A, k)
++                    V = V.T.conj()
+     elif isinstance(A, LinearOperator):
+-        m, n = A.shape
+-        def matvec(x):
+-            return A.matvec(x)
+-        def matveca(x):
+-            return A.rmatvec(x)
+         if eps_or_k < 1:
+             eps = eps_or_k
+             if real:
+-                U, V, S = _backend.iddp_rsvd(eps, m, n, matveca, matvec)
++                U, S, V = _backend.iddp_rsvd(A, eps, rng=rng)
+             else:
+-                if _IS_32BIT:
+-                    raise _32BIT_ERROR
+-                U, V, S = _backend.idzp_rsvd(eps, m, n, matveca, matvec)
++                U, S, V = _backend.idzp_rsvd(A, eps, rng=rng)
+         else:
+             k = int(eps_or_k)
+             if real:
+-                U, V, S = _backend.iddr_rsvd(m, n, matveca, matvec, k)
++                U, S, V = _backend.iddr_rsvd(A, k, rng=rng)
+             else:
+-                if _IS_32BIT:
+-                    raise _32BIT_ERROR
+-                U, V, S = _backend.idzr_rsvd(m, n, matveca, matvec, k)
++                U, S, V = _backend.idzr_rsvd(A, k, rng=rng)
+     else:
+         raise _TYPE_ERROR
+     return U, S, V
+ 
+ 
+-def estimate_rank(A, eps):
++def estimate_rank(A, eps, rng=None):
+     """
+     Estimate matrix rank to a specified relative precision using randomized
+     methods.
+@@ -985,6 +936,8 @@ def estimate_rank(A, eps):
+         with the `rmatvec` method (to apply the matrix adjoint).
+     eps : float
+         Relative error for numerical rank definition.
++    rng : :class:`numpy.random.Generator`
++        NumPy generator for the randomization steps in the algorithm.
+ 
+     Returns
+     -------
+@@ -996,20 +949,19 @@ def estimate_rank(A, eps):
+     real = _is_real(A)
+ 
+     if isinstance(A, np.ndarray):
++        A = _C_contiguous_copy(A)
+         if real:
+-            rank = _backend.idd_estrank(eps, A)
++            rank, _ = _backend.idd_estrank(A, eps, rng=rng)
+         else:
+-            rank = _backend.idz_estrank(eps, A)
++            rank, _ = _backend.idz_estrank(A, eps, rng=rng)
+         if rank == 0:
+             # special return value for nearly full rank
+             rank = min(A.shape)
+         return rank
+     elif isinstance(A, LinearOperator):
+-        m, n = A.shape
+-        matveca = A.rmatvec
+         if real:
+-            return _backend.idd_findrank(eps, m, n, matveca)
++            return _backend.idd_findrank(A, eps, rng=rng)[0]
+         else:
+-            return _backend.idz_findrank(eps, m, n, matveca)
++            return _backend.idz_findrank(A, eps, rng=rng)[0]
+     else:
+         raise _TYPE_ERROR
+diff --git a/scipy/linalg/meson.build b/scipy/linalg/meson.build
+index cc208092e..777edd008 100644
+--- a/scipy/linalg/meson.build
++++ b/scipy/linalg/meson.build
+@@ -111,57 +111,15 @@ py3.extension_module('_flapack',
+ 
+ # TODO: cblas/clapack are built *only* for ATLAS. Why? Is it still needed?
+ 
+-# id_dist contains a copy of FFTPACK, which has type mismatch warnings
+-# that are hard to fix. This code is terrible and noisy during the build,
+-# silence it completely.
+-_suppress_all_warnings = ff.get_supported_arguments('-w')
+-
+-py3.extension_module('_interpolative',
+-  [
+-    'src/id_dist/src/dfft.f',
+-    'src/id_dist/src/id_rand.f',
+-    'src/id_dist/src/id_rtrans.f',
+-    'src/id_dist/src/idd_frm.f',
+-    'src/id_dist/src/idd_house.f',
+-    'src/id_dist/src/idd_id.f',
+-    'src/id_dist/src/idd_id2svd.f',
+-    'src/id_dist/src/idd_qrpiv.f',
+-    'src/id_dist/src/idd_sfft.f',
+-    'src/id_dist/src/idd_snorm.f',
+-    'src/id_dist/src/idd_svd.f',
+-    'src/id_dist/src/iddp_aid.f',
+-    'src/id_dist/src/iddp_asvd.f',
+-    'src/id_dist/src/iddp_rid.f',
+-    'src/id_dist/src/iddp_rsvd.f',
+-    'src/id_dist/src/iddr_aid.f',
+-    'src/id_dist/src/iddr_asvd.f',
+-    'src/id_dist/src/iddr_rid.f',
+-    'src/id_dist/src/iddr_rsvd.f',
+-    'src/id_dist/src/idz_frm.f',
+-    'src/id_dist/src/idz_house.f',
+-    'src/id_dist/src/idz_id.f',
+-    'src/id_dist/src/idz_id2svd.f',
+-    'src/id_dist/src/idz_qrpiv.f',
+-    'src/id_dist/src/idz_sfft.f',
+-    'src/id_dist/src/idz_snorm.f',
+-    'src/id_dist/src/idz_svd.f',
+-    'src/id_dist/src/idzp_aid.f',
+-    'src/id_dist/src/idzp_asvd.f',
+-    'src/id_dist/src/idzp_rid.f',
+-    'src/id_dist/src/idzp_rsvd.f',
+-    'src/id_dist/src/idzr_aid.f',
+-    'src/id_dist/src/idzr_asvd.f',
+-    'src/id_dist/src/idzr_rid.f',
+-    'src/id_dist/src/idzr_rsvd.f',
+-    'src/id_dist/src/prini.f',
+-    f2py_gen.process('interpolative.pyf'),
+-  ],
+-  fortran_args: [fortran_ignore_warnings, _suppress_all_warnings],
++# _decomp_interpolative
++py3.extension_module('_decomp_interpolative',
++  linalg_init_cython_gen.process('_decomp_interpolative.pyx'),
++  c_args: cython_c_args,
++  dependencies: np_dep,
++  c_args: numpy_nodepr_api,
+   link_args: version_link_args,
+-  dependencies: [lapack_dep, fortranobject_dep],
+   override_options: ['b_lto=false'],
+   install: true,
+-  link_language: 'fortran',
+   subdir: 'scipy/linalg'
+ )
+ 
+@@ -278,7 +236,6 @@ python_sources = [
+   '_decomp_schur.py',
+   '_decomp_svd.py',
+   '_expm_frechet.py',
+-  '_interpolative_backend.py',
+   '_matfuncs.py',
+   '_matfuncs_expm.pyi',
+   '_matfuncs_inv_ssq.py',
+diff --git a/scipy/linalg/src/id_dist/README.txt b/scipy/linalg/src/id_dist/README.txt
+deleted file mode 100644
+index 000bb1e5f..000000000
+--- a/scipy/linalg/src/id_dist/README.txt
++++ /dev/null
+@@ -1,6 +0,0 @@
+-Please see the documentation in subdirectory doc of this id_dist directory.
+-
+-At the minimum, please read Subsection 2.1 and Section 3 in the documentation,
+-and beware that the _N.B._'s in the source code comments highlight important
+-information about the routines -- _N.B._ stands for _nota_bene_ (Latin for
+-"note well").
+diff --git a/scipy/linalg/src/id_dist/doc/doc.bib b/scipy/linalg/src/id_dist/doc/doc.bib
+deleted file mode 100644
+index 1ab5cb220..000000000
+--- a/scipy/linalg/src/id_dist/doc/doc.bib
++++ /dev/null
+@@ -1,19 +0,0 @@
+-@book{golub-van_loan,
+-  author = {Gene Golub and Charles {Van L}oan},
+-  title = {Matrix Computations},
+-  edition = {Third},
+-  publisher = {Johns Hopkins University Press},
+-  year = {1996},
+-  address = {Baltimore, Maryland}
+-}
+-
+-@article{halko-martinsson-tropp,
+-  author = {Nathan Halko and {P.-G.} Martinsson and Joel A. Tropp},
+-  title = {Finding structure with randomness: probabilistic algorithms
+-           for constructing approximate matrix decompositions},
+-  journal = {SIAM Review},
+-  volume = {53},
+-  number = {2},
+-  pages = {217--288},
+-  year = {2011}
+-}
+diff --git a/scipy/linalg/src/id_dist/doc/doc.tex b/scipy/linalg/src/id_dist/doc/doc.tex
+deleted file mode 100644
+index 8bcece8c4..000000000
+--- a/scipy/linalg/src/id_dist/doc/doc.tex
++++ /dev/null
+@@ -1,977 +0,0 @@
+-\documentclass[letterpaper,12pt]{article}
+-\usepackage[margin=1in]{geometry}
+-\usepackage{verbatim}
+-\usepackage{amsmath}
+-\usepackage{supertabular}
+-\usepackage{array}
+-
+-\def\T{{\hbox{\scriptsize{\rm T}}}}
+-\def\epsilon{\varepsilon}
+-\def\bigoh{\mathcal{O}}
+-\def\phi{\varphi}
+-\def\st{{\hbox{\scriptsize{\rm st}}}}
+-\def\th{{\hbox{\scriptsize{\rm th}}}}
+-\def\x{\mathbf{x}}
+-
+-
+-\title{ID: A software package for low-rank approximation
+-       of matrices via interpolative decompositions, Version 0.4}
+-\author{Per-Gunnar Martinsson, Vladimir Rokhlin,\\
+-        Yoel Shkolnisky, and Mark Tygert}
+-
+-
+-\begin{document}
+-
+-\maketitle
+-
+-\newpage
+-
+-{\parindent=0pt
+-
+-The present document and all of the software
+-in the accompanying distribution (which is contained in the directory
+-{\tt id\_dist} and its subdirectories, or in the file
+-{\tt id\_dist.tar.gz})\, is
+-
+-\bigskip
+-
+-Copyright \copyright\ 2014 by P.-G. Martinsson, V. Rokhlin,
+-Y. Shkolnisky, and M. Tygert.
+-
+-\bigskip
+-
+-All rights reserved.
+-
+-\bigskip
+-
+-Redistribution and use in source and binary forms, with or without
+-modification, are permitted provided that the following conditions are
+-met:
+-
+-\begin{enumerate}
+-\item Redistributions of source code must retain the above copyright
+-notice, this list of conditions, and the following disclaimer.
+-\item Redistributions in binary form must reproduce the above copyright
+-notice, this list of conditions, and the following disclaimer in the
+-documentation and/or other materials provided with the distribution.
+-\item None of the names of the copyright holders may be used to endorse
+-or promote products derived from this software without specific prior
+-written permission.
+-\end{enumerate}
+-
+-\bigskip
+-
+-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+-EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+-PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS BE
+-LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+-OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+-ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-
+-}
+-
+-\newpage
+-
+-\tableofcontents
+-
+-\newpage
+-
+-
+-
+-\hrule
+-
+-\medskip
+-
+-\centerline{\Large \bf IMPORTANT}
+-
+-\medskip
+-
+-\hrule
+-
+-\medskip
+-
+-\noindent At the minimum, please read Subsection~\ref{warning}
+-and Section~\ref{naming} below, and beware that the {\it N.B.}'s
+-in the source code comments highlight key information about the routines;
+-{\it N.B.} stands for {\it nota bene} (Latin for ``note well'').
+-
+-\medskip
+-
+-\hrule
+-
+-\bigskip
+-
+-
+-
+-\section{Introduction}
+-
+-This software distribution provides Fortran routines
+-for computing low-rank approximations to matrices,
+-in the forms of interpolative decompositions (IDs)
+-and singular value decompositions (SVDs).
+-The routines use algorithms based on the ID.
+-The ID is also commonly known as
+-the approximation obtained via skeletonization,
+-the approximation obtained via subsampling,
+-and the approximation obtained via subset selection.
+-The ID provides many advantages in many applications,
+-and we suspect that it will become increasingly popular
+-once tools for its computation become more widely available.
+-This software distribution includes some such tools,
+-as well as tools for computing low-rank approximations
+-in the form of SVDs.
+-Section~\ref{defs} below defines IDs and SVDs,
+-and provides references to detailed discussions of the algorithms
+-used in this software package.
+-
+-Please beware that normalized power iterations are better suited than
+-the software in this distribution
+-for computing principal component analyses
+-in the typical case when the square of the signal-to-noise ratio
+-is not orders of magnitude greater than both dimensions
+-of the data matrix; see~\cite{halko-martinsson-tropp}.
+-
+-The algorithms used in this distribution have been optimized
+-for accuracy, efficiency, and reliability;
+-as a somewhat counterintuitive consequence, many must be randomized.
+-All randomized codes in this software package succeed
+-with overwhelmingly high probability (see, for example,
+-\cite{halko-martinsson-tropp}).
+-The truly paranoid are welcome to use the routines {\tt idd\_diffsnorm}
+-and {\tt idz\_diffsnorm} to evaluate rapidly the quality
+-of the approximations produced by the randomized algorithms
+-(as done, for example, in the files
+-{\tt idd\_a\_test.f}, {\tt idd\_r\_test.f}, {\tt idz\_a\_test.f},
+-and {\tt idz\_r\_test.f} in the {\tt test} subdirectory
+-of the main directory {\tt id\_dist}).
+-In most circumstances, evaluating the quality of an approximation
+-via routines {\tt idd\_diffsnorm} or {\tt idz\_diffsnorm} is much faster
+-than forming the approximation to be evaluated. Still, we are unaware
+-of any instance in which a properly-compiled routine failed to produce
+-an accurate approximation.
+-To facilitate successful compilation, we encourage the user
+-to read the instructions in the next section,
+-and to read Section~\ref{naming}, too.
+-
+-
+-
+-\section{Compilation instructions}
+-
+-
+-Followed in numerical order, the subsections of this section
+-provide step-by-step instructions for compiling the software
+-under a Unix-compatible operating system.
+-
+-
+-\subsection{Beware that default command-line flags may not be
+-            sufficient for compiling the source codes!}
+-\label{warning}
+-
+-The Fortran source codes in this distribution pass {\tt real*8}
+-variables as integer variables, integers as {\tt real*8}'s,
+-{\tt real*8}'s as {\tt complex*16}'s, and so on.
+-This is common practice in numerical codes, and is not an error;
+-be sure to provide the relevant command-line flags to the compiler
+-(for example, run {\tt fort77} and {\tt f2c} with the flag {\tt -!P}).
+-When following the compilation instructions
+-in Subsection~\ref{makefile_edit} below,
+-be sure to set {\tt FFLAGS} appropriately.
+-
+-
+-\subsection{Install LAPACK}
+-
+-The SVD routines in this distribution depend on LAPACK.
+-Before compiling the present distribution,
+-create the LAPACK and BLAS archive (library) {\tt .a} files;
+-information about installing LAPACK is available
+-at {\tt http://www.netlib.org/lapack/} (and several other web sites).
+-
+-
+-\subsection{Decompress and untar the file {\tt id\_dist.tar.gz}}
+-
+-At the command line, decompress and untar the file
+-{\tt id\_dist.tar.gz} by issuing a command such as
+-{\tt tar -xvvzf id\_dist.tar.gz}.
+-This will create a directory named {\tt id\_dist}.
+-
+-
+-\subsection{Edit the Makefile}
+-\label{makefile_edit}
+-
+-The directory {\tt id\_dist} contains a file named {\tt Makefile}.
+-In {\tt Makefile}, set the following:
+-%
+-\begin{itemize}
+-\item {\tt FC} is the Fortran compiler.
+-\item {\tt FFLAGS} is the set of command-line flags
+-      (specifying optimization settings, for example)
+-      for the Fortran compiler specified by {\tt FC};
+-      please heed the warning in Subsection~\ref{warning} above!
+-\item {\tt BLAS\_LIB} is the file-system path to the BLAS archive
+-      (library) {\tt .a} file.
+-\item {\tt LAPACK\_LIB} is the file-system path to the LAPACK archive
+-      (library) {\tt .a} file.
+-\item {\tt ARCH} is the archiver utility (usually {\tt ar}).
+-\item {\tt ARCHFLAGS} is the set of command-line flags
+-      for the archiver specified by {\tt ARCH} needed
+-      to create an archive (usually {\tt cr}).
+-\item {\tt RANLIB} is to be set to {\tt ranlib}
+-      when {\tt ranlib} is available, and is to be set to {\tt echo}
+-      when {\tt ranlib} is not available.
+-\end{itemize}
+-
+-
+-\subsection{Make and test the libraries}
+-
+-At the command line in a shell that adheres
+-to the Bourne shell conventions for redirection, issue the command
+-``{\tt make clean; make}'' to both create the archive (library)
+-{\tt id\_lib.a} and test it.
+-(In most modern Unix distributions, {\tt sh} is the Bourne shell,
+-or else is fully compatible with the Bourne shell;
+-the Korn shell {\tt ksh} and the Bourne-again shell {\tt bash}
+-also use the Bourne shell conventions for redirection.)
+-{\tt make} places the file {\tt id\_lib.a}
+-in the directory {\tt id\_dist}; the archive (library) file
+-{\tt id\_lib.a} contains machine code for all user-callable routines
+-in this distribution.
+-
+-
+-
+-\section{Naming conventions}
+-\label{naming}
+-
+-The names of routines and files in this distribution
+-start with prefixes, followed by an underscore (``\_'').
+-The prefixes are two to four characters in length,
+-and have the following meanings:
+-%
+-\begin{itemize}
+-\item The first two letters are always ``{\tt id}'',
+-      the name of this distribution.
+-\item The third letter (when present) is either ``{\tt d}''
+-      or ``{\tt z}'';
+-      ``{\tt d}'' stands for double precision ({\tt real*8}),
+-      and ``{\tt z}'' stands for double complex ({\tt complex*16}).
+-\item The fourth letter (when present) is either ``{\tt r}''
+-      or ``{\tt p}'';
+-      ``{\tt r}'' stands for specified rank,
+-      and ``{\tt p}'' stands for specified precision.
+-      The specified rank routines require the user to provide
+-      the rank of the approximation to be constructed,
+-      while the specified precision routines adjust the rank adaptively
+-      to attain the desired precision.
+-\end{itemize}
+-
+-For example, {\tt iddr\_aid} is a {\tt real*8} routine which computes
+-an approximation of specified rank.
+-{\tt idz\_snorm} is a {\tt complex*16} routine.
+-{\tt id\_randperm} is yet another routine in this distribution.
+-
+-
+-
+-\section{Example programs}
+-
+-For examples of how to use the user-callable routines
+-in this distribution, see the source codes in subdirectory {\tt test}
+-of the main directory {\tt id\_dist}.
+-
+-
+-
+-\section{Directory structure}
+-
+-The main {\tt id\_dist} directory contains a Makefile,
+-the auxiliary text files {\tt README.txt} and {\tt size.txt},
+-and the following subdirectories, described in the subsections below:
+-%
+-\begin{enumerate}
+-\item {\tt bin}
+-\item {\tt development}
+-\item {\tt doc}
+-\item {\tt src}
+-\item {\tt test}
+-\item {\tt tmp}
+-\end{enumerate}
+-%
+-If a ``{\tt make all}'' command has completed successfully,
+-then the main {\tt id\_dist} directory will also contain
+-an archive (library) file {\tt id\_lib.a} containing machine code
+-for all of the user-callable routines.
+-
+-
+-\subsection{Subdirectory {\tt bin}}
+-
+-Once all of the libraries have been made via the Makefile
+-in the main {\tt id\_dist} directory,
+-the subdirectory {\tt bin} will contain object files (machine code),
+-each compiled from the corresponding file of source code
+-in the subdirectory {\tt src} of {\tt id\_dist}.
+-
+-
+-\subsection{Subdirectory {\tt development}}
+-
+-Each Fortran file in the subdirectory {\tt development}
+-(except for {\tt dfft.f} and {\tt prini.f})
+-specifies its dependencies at the top, then provides a main program
+-for testing and debugging, and finally provides source code
+-for a library of user-callable subroutines.
+-The Fortran file {\tt dfft.f} is a copy of P. N. Swarztrauber's FFTPACK library
+-for computing fast Fourier transforms.
+-The Fortran file {\tt prini.f} is a copy of V. Rokhlin's library
+-of formatted printing routines.
+-Both {\tt dfft.f} (version 4) and {\tt prini.f} are in the public domain.
+-The shell script {\tt RUNME.sh} runs shell scripts {\tt make\_src.sh}
+-and {\tt make\_test.sh}, which fill the subdirectories {\tt src}
+-and {\tt test} of the main directory {\tt id\_dist}
+-with source codes for user-callable routines
+-and with the main program testing codes.
+-
+-
+-\subsection{Subdirectory {\tt doc}}
+-
+-Subdirectory {\tt doc} contains this documentation,
+-supplementing comments in the source codes.
+-
+-
+-\subsection{Subdirectory {\tt src}}
+-
+-The files in the subdirectory {\tt src} provide source code
+-for software libraries. Each file in the subdirectory {\tt src}
+-(except for {\tt dfft.f} and {\tt prini.f}) is
+-the bottom part of the corresponding file
+-in the subdirectory {\tt development} of {\tt id\_dist}.
+-The file {\tt dfft.f} is just a copy
+-of P. N. Swarztrauber's FFTPACK library
+-for computing fast Fourier transforms.
+-The file {\tt prini.f} is a copy of V. Rokhlin's library
+-of formatted printing routines.
+-Both {\tt dfft.f} (version 4) and {\tt prini.f} are in the public domain.
+-
+-
+-\subsection{Subdirectory {\tt test}}
+-
+-The files in subdirectory {\tt test} provide source code
+-for testing and debugging. Each file in subdirectory {\tt test} is
+-the top part of the corresponding file
+-in subdirectory {\tt development} of {\tt id\_dist},
+-and provides a main program and a list of its dependencies.
+-These codes provide examples of how to call the user-callable routines.
+-
+-
+-
+-\section{Catalog of the routines}
+-
+-The main routines for decomposing {\tt real*8} matrices are:
+-%
+-\begin{enumerate}
+-%
+-\item IDs of arbitrary (generally dense) matrices:
+-{\tt iddp\_id}, {\tt iddr\_id}, {\tt iddp\_aid}, {\tt iddr\_aid}
+-%
+-\item IDs of matrices that may be rapidly applied to arbitrary vectors
+-(as may the matrices' transposes):
+-{\tt iddp\_rid}, {\tt iddr\_rid}
+-%
+-\item SVDs of arbitrary (generally dense) matrices:
+-{\tt iddp\_svd}, {\tt iddr\_svd}, {\tt iddp\_asvd},\\{\tt iddr\_asvd}
+-%
+-\item SVDs of matrices that may be rapidly applied to arbitrary vectors
+-(as may the matrices' transposes):
+-{\tt iddp\_rsvd}, {\tt iddr\_rsvd}
+-%
+-\end{enumerate}
+-
+-Similarly, the main routines for decomposing {\tt complex*16} matrices
+-are:
+-%
+-\begin{enumerate}
+-%
+-\item IDs of arbitrary (generally dense) matrices:
+-{\tt idzp\_id}, {\tt idzr\_id}, {\tt idzp\_aid}, {\tt idzr\_aid}
+-%
+-\item IDs of matrices that may be rapidly applied to arbitrary vectors
+-(as may the matrices' adjoints):
+-{\tt idzp\_rid}, {\tt idzr\_rid}
+-%
+-\item SVDs of arbitrary (generally dense) matrices:
+-{\tt idzp\_svd}, {\tt idzr\_svd}, {\tt idzp\_asvd},\\{\tt idzr\_asvd}
+-%
+-\item SVDs of matrices that may be rapidly applied to arbitrary vectors
+-(as may the matrices' adjoints):
+-{\tt idzp\_rsvd}, {\tt idzr\_rsvd}
+-%
+-\end{enumerate}
+-
+-This distribution also includes routines for constructing pivoted $QR$
+-decompositions (in {\tt idd\_qrpiv.f} and {\tt idz\_qrpiv.f}), for
+-estimating the spectral norms of matrices that may be applied rapidly
+-to arbitrary vectors as may their adjoints (in {\tt idd\_snorm.f}
+-and {\tt idz\_snorm.f}), for converting IDs to SVDs (in
+-{\tt idd\_id2svd.f} and {\tt idz\_id2svd.f}), and for computing rapidly
+-arbitrary subsets of the entries of the discrete Fourier transforms
+-of vectors (in {\tt idd\_sfft.f} and {\tt idz\_sfft.f}).
+-
+-
+-\subsection{List of the routines}
+-
+-The following is an alphabetical list of the routines
+-in this distribution, together with brief descriptions
+-of their functionality and the names of the files containing
+-the routines' source code:
+-
+-\begin{center}
+-%
+-\tablehead{\bf Routine & \bf Description & \bf Source file \\}
+-\tabletail{\hline}
+-%
+-\begin{supertabular}{>{\raggedright}p{1.2in} p{.53\textwidth} l}
+-%
+-\hline
+-{\tt id\_frand} & generates pseudorandom numbers drawn uniformly from
+-the interval $[0,1]$; this routine is more efficient than routine
+-{\tt id\_srand}, but cannot generate fewer than 55 pseudorandom numbers
+-per call & {\tt id\_rand.f} \\\hline
+-%
+-{\tt id\_frandi} & initializes the seed values for routine
+-{\tt id\_frand} to specified values & {\tt id\_rand.f} \\\hline
+-%
+-{\tt id\_frando} & initializes the seed values for routine
+-{\tt id\_frand} to their original, default values & {\tt id\_rand.f}
+-\\\hline
+-%
+-{\tt id\_randperm} & generates a uniformly random permutation &
+-{\tt id\_rand.f} \\\hline
+-%
+-{\tt id\_srand} & generates pseudorandom numbers drawn uniformly from
+-the interval $[0,1]$; this routine is less efficient than routine
+-{\tt id\_frand}, but can generate fewer than 55 pseudorandom numbers
+-per call & {\tt id\_rand.f} \\\hline
+-%
+-{\tt id\_srandi} & initializes the seed values for routine
+-{\tt id\_srand} to specified values & {\tt id\_rand.f} \\\hline
+-%
+-{\tt id\_srando} & initializes the seed values for routine
+-{\tt id\_srand} to their original, default values & {\tt id\_rand.f}
+-\\\hline
+-%
+-{\tt idd\_copycols} & collects together selected columns of a matrix &
+-{\tt idd\_id.f} \\\hline
+-%
+-{\tt idd\_diffsnorm} & estimates the spectral norm of the difference
+-between two matrices specified by routines for applying the matrices
+-and their transposes to arbitrary vectors; this routine uses the power
+-method with a random starting vector & {\tt idd\_snorm.f} \\\hline
+-%
+-{\tt idd\_enorm} & calculates the Euclidean norm of a vector &
+-{\tt idd\_snorm.f} \\\hline
+-%
+-{\tt idd\_estrank} & estimates the numerical rank of an arbitrary
+-(generally dense) matrix to a specified precision; this routine is
+-randomized, and must be initialized with routine {\tt idd\_frmi} &
+-{\tt iddp\_aid.f} \\\hline
+-%
+-{\tt idd\_frm} & transforms a vector into a vector which is
+-sufficiently scrambled to be subsampled, via a composition of Rokhlin's
+-random transform, random subselection, and a fast Fourier transform &
+-{\tt idd\_frm.f} \\\hline
+-%
+-{\tt idd\_frmi} & initializes routine {\tt idd\_frm} & {\tt idd\_frm.f}
+-\\\hline
+-%
+-{\tt idd\_getcols} & collects together selected columns of a matrix
+-specified by a routine for applying the matrix to arbitrary vectors &
+-{\tt idd\_id.f} \\\hline
+-%
+-{\tt idd\_house} & calculates the vector and scalar needed to apply the
+-Householder transformation reflecting a given vector into its first
+-entry & {\tt idd\_house.f} \\\hline
+-%
+-{\tt idd\_houseapp} & applies a Householder matrix to a vector &
+-{\tt idd\_house.f} \\\hline
+-%
+-{\tt idd\_id2svd} & converts an approximation to a matrix in the form
+-of an ID into an approximation in the form of an SVD &
+-{\tt idd\_id2svd.f} \\\hline
+-%
+-{\tt idd\_ldiv} & finds the greatest integer less than or equal to a
+-specified integer, that is divisible by another (larger) specified
+-integer & {\tt idd\_sfft.f} \\\hline
+-%
+-{\tt idd\_pairsamps} & calculates the indices of the pairs of integers
+-that the individual integers in a specified set belong to &
+-{\tt idd\_frm.f} \\\hline
+-%
+-{\tt idd\_permmult} & multiplies together a bunch of permutations &
+-{\tt idd\_qrpiv.f} \\\hline
+-%
+-{\tt idd\_qinqr} & reconstructs the $Q$ matrix in a $QR$ decomposition
+-from the output of routines {\tt iddp\_qrpiv} or {\tt iddr\_qrpiv} &
+-{\tt idd\_qrpiv.f} \\\hline
+-%
+-{\tt idd\_qrmatmat} & applies to multiple vectors collected together as
+-a matrix the $Q$ matrix (or its transpose) in the $QR$ decomposition of
+-a matrix, as described by the output of routines {\tt iddp\_qrpiv} or
+-{\tt iddr\_qrpiv}; to apply $Q$ (or its transpose) to a single vector
+-without having to provide a work array, use routine {\tt idd\_qrmatvec}
+-instead & {\tt idd\_qrpiv.f} \\\hline
+-%
+-{\tt idd\_qrmatvec} & applies to a single vector the $Q$ matrix (or its
+-transpose) in the $QR$ decomposition of a matrix, as described by the
+-output of routines {\tt iddp\_qrpiv} or {\tt iddr\_qrpiv}; to apply $Q$ 
+-(or its transpose) to several vectors efficiently, use routine
+-{\tt idd\_qrmatmat} instead & {\tt idd\_qrpiv.f} \\\hline
+-%
+-{\tt idd\_random\_} {\tt transf} & applies rapidly a
+-random orthogonal matrix to a user-supplied vector & {\tt id\_rtrans.f}
+-\\\hline
+-%
+-{\tt idd\_random\_ transf\_init} & \raggedright initializes routines
+-{\tt idd\_random\_transf} and {\tt idd\_random\_transf\_inverse} &
+-{\tt id\_rtrans.f} \\\hline
+-%
+-{\tt idd\_random\_} {\tt transf\_inverse} & applies
+-rapidly the inverse of the operator applied by routine
+-{\tt idd\_random\_transf} & {\tt id\_rtrans.f} \\\hline
+-%
+-{\tt idd\_reconid} & reconstructs a matrix from its ID &
+-{\tt idd\_id.f} \\\hline
+-%
+-{\tt idd\_reconint} & constructs $P$ in the ID $A = B \, P$, where the
+-columns of $B$ are a subset of the columns of $A$, and $P$ is the
+-projection coefficient matrix, given {\tt list}, {\tt krank}, and
+-{\tt proj} output by routines {\tt iddr\_id}, {\tt iddp\_id},
+-{\tt iddr\_aid}, {\tt iddp\_aid}, {\tt iddr\_rid}, or {\tt iddp\_rid} &
+-{\tt idd\_id.f} \\\hline
+-%
+-{\tt idd\_sfft} & rapidly computes a subset of the entries of the
+-discrete Fourier transform of a vector, composed with permutation
+-matrices both on input and on output & {\tt idd\_sfft.f} \\\hline
+-%
+-{\tt idd\_sffti} & initializes routine {\tt idd\_sfft} &
+-{\tt idd\_sfft.f} \\\hline
+-%
+-{\tt idd\_sfrm} & transforms a vector into a scrambled vector of
+-specified length, via a composition of Rokhlin's random transform,
+-random subselection, and a fast Fourier transform & {\tt idd\_frm.f}
+-\\\hline
+-%
+-{\tt idd\_sfrmi} & initializes routine {\tt idd\_sfrm} &
+-{\tt idd\_frm.f} \\\hline
+-%
+-{\tt idd\_snorm} & estimates the spectral norm of a matrix specified by
+-routines for applying the matrix and its transpose to arbitrary
+-vectors; this routine uses the power method with a random starting
+-vector & {\tt idd\_snorm.f} \\\hline
+-%
+-{\tt iddp\_aid} & computes the ID of an arbitrary (generally dense)
+-matrix, to a specified precision; this routine is randomized, and must
+-be initialized with routine {\tt idd\_frmi} & {\tt iddp\_aid.f}
+-\\\hline
+-%
+-{\tt iddp\_asvd} & computes the SVD of an arbitrary (generally dense)
+-matrix, to a specified precision; this routine is randomized, and must
+-be initialized with routine {\tt idd\_frmi} & {\tt iddp\_asvd.f}
+-\\\hline
+-%
+-{\tt iddp\_id} & computes the ID of an arbitrary (generally dense)
+-matrix, to a specified precision; this routine is often less efficient
+-than routine {\tt iddp\_aid} & {\tt idd\_id.f} \\\hline
+-%
+-{\tt iddp\_qrpiv} & computes the pivoted $QR$ decomposition of an
+-arbitrary (generally dense) matrix via Householder transformations,
+-stopping at a specified precision of the decomposition &
+-{\tt idd\_qrpiv.f} \\\hline
+-%
+-{\tt iddp\_rid} & computes the ID, to a specified precision, of a
+-matrix specified by a routine for applying its transpose to arbitrary
+-vectors; this routine is randomized & {\tt iddp\_rid.f} \\\hline
+-%
+-{\tt iddp\_rsvd} & computes the SVD, to a specified precision, of a
+-matrix specified by routines for applying the matrix and its transpose
+-to arbitrary vectors; this routine is randomized & {\tt iddp\_rsvd.f}
+-\\\hline
+-%
+-{\tt iddp\_svd} & computes the SVD of an arbitrary (generally dense)
+-matrix, to a specified precision; this routine is often less efficient
+-than routine {\tt iddp\_asvd} & {\tt idd\_svd.f} \\\hline
+-%
+-{\tt iddr\_aid} & computes the ID of an arbitrary (generally dense)
+-matrix, to a specified rank; this routine is randomized, and must be
+-initialized by routine {\tt iddr\_aidi} & {\tt iddr\_aid.f} \\\hline
+-%
+-{\tt iddr\_aidi} & initializes routine {\tt iddr\_aid} &
+-{\tt iddr\_aid.f} \\\hline
+-%
+-{\tt iddr\_asvd} & computes the SVD of an arbitrary (generally dense)
+-matrix, to a specified rank; this routine is randomized, and must be
+-initialized with routine {\tt idd\_aidi} & {\tt iddr\_asvd.f}
+-\\\hline
+-%
+-{\tt iddr\_id} & computes the ID of an arbitrary (generally dense)
+-matrix, to a specified rank; this routine is often less efficient than
+-routine {\tt iddr\_aid} & {\tt idd\_id.f} \\\hline
+-%
+-{\tt iddr\_qrpiv} & computes the pivoted $QR$ decomposition of an
+-arbitrary (generally dense) matrix via Householder transformations,
+-stopping at a specified rank of the decomposition & {\tt idd\_qrpiv.f}
+-\\\hline
+-%
+-{\tt iddr\_rid} & computes the ID, to a specified rank, of a matrix
+-specified by a routine for applying its transpose to arbitrary vectors;
+-this routine is randomized & {\tt iddr\_rid.f} \\\hline
+-%
+-{\tt iddr\_rsvd} & computes the SVD, to a specified rank, of a matrix
+-specified by routines for applying the matrix and its transpose to
+-arbitrary vectors; this routine is randomized & {\tt iddr\_rsvd.f}
+-\\\hline
+-%
+-{\tt iddr\_svd} & computes the SVD of an arbitrary (generally dense)
+-matrix, to a specified rank; this routine is often less efficient than
+-routine {\tt iddr\_asvd} & {\tt idd\_svd.f} \\\hline
+-%
+-{\tt idz\_copycols} & collects together selected columns of a matrix &
+-{\tt idz\_id.f} \\\hline
+-%
+-{\tt idz\_diffsnorm} & estimates the spectral norm of the difference
+-between two matrices specified by routines for applying the matrices
+-and their adjoints to arbitrary vectors; this routine uses the power
+-method with a random starting vector & {\tt idz\_snorm.f} \\\hline
+-%
+-{\tt idz\_enorm} & calculates the Euclidean norm of a vector &
+-{\tt idz\_snorm.f} \\\hline
+-%
+-{\tt idz\_estrank} & estimates the numerical rank of an arbitrary
+-(generally dense) matrix to a specified precision; this routine is
+-randomized, and must be initialized with routine {\tt idz\_frmi} &
+-{\tt idzp\_aid.f} \\\hline
+-%
+-{\tt idz\_frm} & transforms a vector into a vector which is
+-sufficiently scrambled to be subsampled, via a composition of Rokhlin's
+-random transform, random subselection, and a fast Fourier transform &
+-{\tt idz\_frm.f} \\\hline
+-%
+-{\tt idz\_frmi} & initializes routine {\tt idz\_frm} & {\tt idz\_frm.f}
+-\\\hline
+-%
+-{\tt idz\_getcols} & collects together selected columns of a matrix
+-specified by a routine for applying the matrix to arbitrary vectors &
+-{\tt idz\_id.f} \\\hline
+-%
+-{\tt idz\_house} & calculates the vector and scalar needed to apply the
+-Householder transformation reflecting a given vector into its first
+-entry & {\tt idz\_house.f} \\\hline
+-%
+-{\tt idz\_houseapp} & applies a Householder matrix to a vector &
+-{\tt idz\_house.f} \\\hline
+-%
+-{\tt idz\_id2svd} & converts an approximation to a matrix in the form
+-of an ID into an approximation in the form of an SVD &
+-{\tt idz\_id2svd.f} \\\hline
+-%
+-{\tt idz\_ldiv} & finds the greatest integer less than or equal to a
+-specified integer, that is divisible by another (larger) specified
+-integer & {\tt idz\_sfft.f} \\\hline
+-%
+-{\tt idz\_permmult} & multiplies together a bunch of permutations &
+-{\tt idz\_qrpiv.f} \\\hline
+-%
+-{\tt idz\_qinqr} & reconstructs the $Q$ matrix in a $QR$ decomposition
+-from the output of routines {\tt idzp\_qrpiv} or {\tt idzr\_qrpiv} &
+-{\tt idz\_qrpiv.f} \\\hline
+-%
+-{\tt idz\_qrmatmat} & applies to multiple vectors collected together as
+-a matrix the $Q$ matrix (or its adjoint) in the $QR$ decomposition of
+-a matrix, as described by the output of routines {\tt idzp\_qrpiv} or
+-{\tt idzr\_qrpiv}; to apply $Q$ (or its adjoint) to a single vector
+-without having to provide a work array, use routine {\tt idz\_qrmatvec}
+-instead & {\tt idz\_qrpiv.f} \\\hline
+-%
+-{\tt idz\_qrmatvec} & applies to a single vector the $Q$ matrix (or its
+-adjoint) in the $QR$ decomposition of a matrix, as described by the
+-output of routines {\tt idzp\_qrpiv} or {\tt idzr\_qrpiv}; to apply $Q$ 
+-(or its adjoint) to several vectors efficiently, use routine
+-{\tt idz\_qrmatmat} instead & {\tt idz\_qrpiv.f} \\\hline
+-%
+-{\tt idz\_random\_ transf} & applies rapidly a random unitary matrix to
+-a user-supplied vector & {\tt id\_rtrans.f} \\\hline
+-%
+-{\tt idz\_random\_ transf\_init} & \raggedright initializes routines
+-{\tt idz\_random\_transf} and {\tt idz\_random\_transf\_inverse} &
+-{\tt id\_rtrans.f} \\\hline
+-%
+-{\tt idz\_random\_ transf\_inverse} & applies rapidly the inverse of
+-the operator applied by routine {\tt idz\_random\_transf} &
+-{\tt id\_rtrans.f} \\\hline
+-%
+-{\tt idz\_reconid} & reconstructs a matrix from its ID &
+-{\tt idz\_id.f} \\\hline
+-%
+-{\tt idz\_reconint} & constructs $P$ in the ID $A = B \, P$, where the
+-columns of $B$ are a subset of the columns of $A$, and $P$ is the
+-projection coefficient matrix, given {\tt list}, {\tt krank}, and
+-{\tt proj} output by routines {\tt idzr\_id}, {\tt idzp\_id},
+-{\tt idzr\_aid}, {\tt idzp\_aid}, {\tt idzr\_rid}, or {\tt idzp\_rid} &
+-{\tt idz\_id.f} \\\hline
+-%
+-{\tt idz\_sfft} & rapidly computes a subset of the entries of the
+-discrete Fourier transform of a vector, composed with permutation
+-matrices both on input and on output & {\tt idz\_sfft.f} \\\hline
+-%
+-{\tt idz\_sffti} & initializes routine {\tt idz\_sfft} &
+-{\tt idz\_sfft.f} \\\hline
+-%
+-{\tt idz\_sfrm} & transforms a vector into a scrambled vector of
+-specified length, via a composition of Rokhlin's random transform,
+-random subselection, and a fast Fourier transform & {\tt idz\_frm.f}
+-\\\hline
+-%
+-{\tt idz\_sfrmi} & initializes routine {\tt idz\_sfrm} &
+-{\tt idz\_frm.f} \\\hline
+-%
+-{\tt idz\_snorm} & estimates the spectral norm of a matrix specified by
+-routines for applying the matrix and its adjoint to arbitrary
+-vectors; this routine uses the power method with a random starting
+-vector & {\tt idz\_snorm.f} \\\hline
+-%
+-{\tt idzp\_aid} & computes the ID of an arbitrary (generally dense)
+-matrix, to a specified precision; this routine is randomized, and must
+-be initialized with routine {\tt idz\_frmi} & {\tt idzp\_aid.f}
+-\\\hline
+-%
+-{\tt idzp\_asvd} & computes the SVD of an arbitrary (generally dense)
+-matrix, to a specified precision; this routine is randomized, and must
+-be initialized with routine {\tt idz\_frmi} & {\tt idzp\_asvd.f}
+-\\\hline
+-%
+-{\tt idzp\_id} & computes the ID of an arbitrary (generally dense)
+-matrix, to a specified precision; this routine is often less efficient
+-than routine {\tt idzp\_aid} & {\tt idz\_id.f} \\\hline
+-%
+-{\tt idzp\_qrpiv} & computes the pivoted $QR$ decomposition of an
+-arbitrary (generally dense) matrix via Householder transformations,
+-stopping at a specified precision of the decomposition &
+-{\tt idz\_qrpiv.f} \\\hline
+-%
+-{\tt idzp\_rid} & computes the ID, to a specified precision, of a
+-matrix specified by a routine for applying its adjoint to arbitrary
+-vectors; this routine is randomized & {\tt idzp\_rid.f} \\\hline
+-%
+-{\tt idzp\_rsvd} & computes the SVD, to a specified precision, of a
+-matrix specified by routines for applying the matrix and its adjoint
+-to arbitrary vectors; this routine is randomized & {\tt idzp\_rsvd.f}
+-\\\hline
+-%
+-{\tt idzp\_svd} & computes the SVD of an arbitrary (generally dense)
+-matrix, to a specified precision; this routine is often less efficient
+-than routine {\tt idzp\_asvd} & {\tt idz\_svd.f} \\\hline
+-%
+-{\tt idzr\_aid} & computes the ID of an arbitrary (generally dense)
+-matrix, to a specified rank; this routine is randomized, and must be
+-initialized by routine {\tt idzr\_aidi} & {\tt idzr\_aid.f} \\\hline
+-%
+-{\tt idzr\_aidi} & initializes routine {\tt idzr\_aid} &
+-{\tt idzr\_aid.f} \\\hline
+-%
+-{\tt idzr\_asvd} & computes the SVD of an arbitrary (generally dense)
+-matrix, to a specified rank; this routine is randomized, and must be
+-initialized with routine {\tt idz\_aidi} & {\tt idzr\_asvd.f}
+-\\\hline
+-%
+-{\tt idzr\_id} & computes the ID of an arbitrary (generally dense)
+-matrix, to a specified rank; this routine is often less efficient than
+-routine {\tt idzr\_aid} & {\tt idz\_id.f} \\\hline
+-%
+-{\tt idzr\_qrpiv} & computes the pivoted $QR$ decomposition of an
+-arbitrary (generally dense) matrix via Householder transformations,
+-stopping at a specified rank of the decomposition & {\tt idz\_qrpiv.f}
+-\\\hline
+-%
+-{\tt idzr\_rid} & computes the ID, to a specified rank, of a matrix
+-specified by a routine for applying its adjoint to arbitrary vectors;
+-this routine is randomized & {\tt idzr\_rid.f} \\\hline
+-%
+-{\tt idzr\_rsvd} & computes the SVD, to a specified rank, of a matrix
+-specified by routines for applying the matrix and its adjoint to
+-arbitrary vectors; this routine is randomized & {\tt idzr\_rsvd.f}
+-\\\hline
+-%
+-{\tt idzr\_svd} & computes the SVD of an arbitrary (generally dense)
+-matrix, to a specified rank; this routine is often less efficient than
+-routine {\tt idzr\_asvd} & {\tt idz\_svd.f} \\
+-%
+-\end{supertabular}
+-\end{center}
+-
+-
+-
+-\section{Documentation in the source codes}
+-
+-Each routine in the source codes includes documentation
+-in the comments immediately following the declaration
+-of the subroutine's calling sequence.
+-This documentation describes the purpose of the routine,
+-the input and output variables, and the required work arrays (if any). 
+-This documentation also cites relevant references.
+-Please pay attention to the {\it N.B.}'s;
+-{\it N.B.} stands for {\it nota bene} (Latin for ``note well'')
+-and highlights important information about the routines.
+-
+-
+-
+-\section{Notation and decompositions}
+-\label{defs}
+-
+-This section sets notational conventions employed
+-in this documentation and the associated software,
+-and defines both the singular value decomposition (SVD)
+-and the interpolative decomposition (ID).
+-For information concerning other mathematical objects
+-used in the code (such as Householder transformations,
+-pivoted $QR$ decompositions, and discrete and fast Fourier transforms
+---- DFTs and FFTs), see, for example,~\cite{golub-van_loan}.
+-For detailed descriptions and proofs of the mathematical facts
+-discussed in the present section, see, for example,
+-\cite{golub-van_loan} and the references
+-in~\cite{halko-martinsson-tropp}.
+-
+-Throughout this document and the accompanying software distribution,
+-$\| \x \|$ always denotes the Euclidean norm of the vector $\x$,
+-and $\| A \|$ always denotes the spectral norm of the matrix $A$.
+-Subsection~\ref{Euclidean} below defines the Euclidean norm;
+-Subsection~\ref{spectral} below defines the spectral norm.
+-We use $A^*$ to denote the adjoint of the matrix $A$.
+-
+-
+-\subsection{Euclidean norm}
+-\label{Euclidean}
+-
+-For any positive integer $n$, and vector $\x$ of length $n$,
+-the Euclidean ($l^2$) norm $\| \x \|$ is
+-%
+-\begin{equation}
+-\| \x \| = \sqrt{ \sum_{k=1}^n |x_k|^2 },
+-\end{equation}
+-%
+-where $x_1$,~$x_2$, \dots, $x_{n-1}$,~$x_n$ are the entries of $\x$.
+-
+-
+-\subsection{Spectral norm}
+-\label{spectral}
+-
+-For any positive integers $m$ and $n$, and $m \times n$ matrix $A$,
+-the spectral ($l^2$ operator) norm $\| A \|$ is
+-%
+-\begin{equation}
+-\| A_{m \times n} \|
+-= \max \frac{\| A_{m \times n} \, \x_{n \times 1} \|}
+-            {\| \x_{n \times 1} \|},
+-\end{equation}
+-%
+-where the $\max$ is taken over all $n \times 1$ column vectors $\x$
+-such that $\| \x \| \ne 0$.
+-
+-
+-\subsection{Singular value decomposition (SVD)}
+-
+-For any positive real number $\epsilon$,
+-positive integers $k$, $m$, and $n$ with $k \le m$ and $k \le n$,
+-and any $m \times n$ matrix $A$,
+-a rank-$k$ approximation to $A$ in the form of an SVD
+-(to precision $\epsilon$) consists of an $m \times k$ matrix $U$
+-whose columns are orthonormal, an $n \times k$ matrix $V$
+-whose columns are orthonormal, and a diagonal $k \times k$ matrix
+-$\Sigma$ with diagonal entries
+-$\Sigma_{1,1} \ge \Sigma_{2,2} \ge \dots \ge \Sigma_{n-1,n-1}
+-                                         \ge \Sigma_{n,n} \ge 0$,
+-such that
+-%
+-\begin{equation}
+-\| A_{m \times n} - U_{m \times k} \, \Sigma_{k \times k}
+-                 \, (V^*)_{k \times n} \| \le \epsilon.
+-\end{equation}
+-%
+-The product $U \, \Sigma \, V^*$ is known as an SVD.
+-The columns of $U$ are known as left singular vectors;
+-the columns of $V$ are known as right singular vectors.
+-The diagonal entries of $\Sigma$ are known as singular values.
+-
+-When $k = m$ or $k = n$, and $A = U \, \Sigma \, V^*$,
+-then $U \, \Sigma \, V^*$ is known as the SVD
+-of $A$; the columns of $U$ are the left singular vectors of $A$,
+-the columns of $V$ are the right singular vectors of $A$,
+-and the diagonal entries of $\Sigma$ are the singular values of $A$.
+-For any positive integer $k$ with $k < m$ and $k < n$,
+-there exists a rank-$k$ approximation to $A$ in the form of an SVD,
+-to precision $\sigma_{k+1}$, where $\sigma_{k+1}$ is the $(k+1)^\st$
+-greatest singular value of $A$.
+-
+-
+-\subsection{Interpolative decomposition (ID)}
+-
+-For any positive real number $\epsilon$,
+-positive integers $k$, $m$, and $n$ with $k \le m$ and $k \le n$,
+-and any $m \times n$ matrix $A$,
+-a rank-$k$ approximation to $A$ in the form of an ID
+-(to precision $\epsilon$) consists of a $k \times n$ matrix $P$,
+-and an $m \times k$ matrix $B$ whose columns constitute a subset
+-of the columns of $A$, such that
+-%
+-\begin{enumerate}
+-\item $\| A_{m \times n} - B_{m \times k} \, P_{k \times n} \|
+-      \le \epsilon$,
+-\item some subset of the columns of $P$ makes up the $k \times k$
+-      identity matrix, and
+-\item every entry of $P$ has an absolute value less than or equal
+-      to a reasonably small positive real number, say 2.
+-\end{enumerate}
+-%
+-The product $B \, P$ is known as an ID.
+-The matrix $P$ is known as the projection or interpolation matrix
+-of the ID. Property~1 above approximates each column of $A$
+-via a linear combination of the columns of $B$
+-(which are themselves columns of $A$), with the coefficients
+-in the linear combination given by the entries of $P$.
+-
+-The interpolative decomposition is ``interpolative''
+-due to Property~2 above. The ID is numerically stable
+-due to Property~3 above.
+-It follows from Property~2 that the least ($k^\th$ greatest) singular value
+-of $P$ is at least 1. Combining Properties~2 and~3 yields that
+-%
+-\begin{equation}
+-\| P_{k \times n} \| \le \sqrt{4k(n-k)+1}.
+-\end{equation}
+-
+-When $k = m$ or $k = n$, and $A = B \, P$,
+-then $B \, P$ is known as the ID of $A$.
+-For any positive integer $k$ with $k < m$ and $k < n$,
+-there exists a rank-$k$ approximation to $A$ in the form of an ID,
+-to precision $\sqrt{k(n-k)+1} \; \sigma_{k+1}$,
+-where $\sigma_{k+1}$ is the $(k+1)^\st$ greatest singular value of $A$
+-(in fact, there exists an ID in which every entry
+-of the projection matrix $P$ has an absolute value less than or equal
+-to 1).
+-
+-
+-
+-\section{Bug reports, feedback, and support}
+-
+-Please let us know about errors in the software or in the documentation
+-via e-mail to {\tt tygert@aya.yale.edu}.
+-We would also appreciate hearing about particular applications of the codes,
+-especially in the form of journal articles
+-e-mailed to {\tt tygert@aya.yale.edu}.
+-Mathematical and technical support may also be available via e-mail. Enjoy!
+-
+-
+-
+-\bibliographystyle{siam}
+-\bibliography{doc}
+-
+-
+-\end{document}
+diff --git a/scipy/linalg/src/id_dist/doc/supertabular.sty b/scipy/linalg/src/id_dist/doc/supertabular.sty
+deleted file mode 100644
+index ac2638c23..000000000
+--- a/scipy/linalg/src/id_dist/doc/supertabular.sty
++++ /dev/null
+@@ -1,483 +0,0 @@
+-%%
+-%% This is file `supertabular.sty',
+-%% generated with the docstrip utility.
+-%%
+-%% The original source files were:
+-%%
+-%% supertabular.dtx  (with options: `package')
+-%% Copyright (C) 1989-2004 Johannes Braams. All rights reserved.
+-%% 
+-%% This file was generated from file(s) of the supertabular package.
+-%% -----------------------------------------------------------------
+-%% 
+-%% It may be distributed and/or modified under the
+-%% conditions of the LaTeX Project Public License, either version 1.3
+-%% of this license or (at your option) any later version.
+-%% The latest version of this license is in
+-%%   http://www.latex-project.org/lppl.txt
+-%% and version 1.3 or later is part of all distributions of LaTeX
+-%% version 2003/12/01 or later.
+-%% 
+-%% This work has the LPPL maintenance status "maintained".
+-%% 
+-%% The Current Maintainer of this work is Johannes Braams.
+-%% 
+-%% This file may only be distributed together with a copy of the
+-%% supertabular package. You may however distribute the supertabular package
+-%% without such generated files.
+-%% 
+-%% The list of all files belonging to the supertabular package is
+-%% given in the file `manifest.txt.
+-%% 
+-%% The list of derived (unpacked) files belonging to the distribution
+-%% and covered by LPPL is defined by the unpacking scripts (with
+-%% extension .ins) which are part of the distribution.
+-%% Sourcefile `supertabular.dtx'.
+-%%
+-%% Copyright (C) 1988 by Theo Jurriens
+-%% Copyright (C) 1990-2004 by Johannes Braams texniek at braams.cistron.nl
+-%%                            Kersengaarde 33
+-%%                            2723 BP Zoetermeer NL
+-%%                       all rights reserved.
+-%%
+-%%
+-\NeedsTeXFormat{LaTeX2e}
+-\ProvidesPackage{supertabular}
+-              [2004/02/20 v4.1e the supertabular environment]
+-\newcount\c@tracingst
+-\DeclareOption{errorshow}{\c@tracingst\z@}
+-\DeclareOption{pageshow}{\c@tracingst\tw@}
+-\DeclareOption{debugshow}{\c@tracingst5\relax}
+-\ProcessOptions
+-\newif\if@topcaption \@topcaptiontrue
+-\def\topcaption{\@topcaptiontrue\tablecaption}
+-\def\bottomcaption{\@topcaptionfalse\tablecaption}
+-\long\def\tablecaption{%
+-  \refstepcounter{table}\@dblarg{\@xtablecaption}}
+-\long\def\@xtablecaption[#1]#2{%
+-  \long\gdef\@process@tablecaption{\ST@caption{table}[#1]{#2}}}
+-\global\let\@process@tablecaption\relax
+-\newif\ifST@star
+-\newif\ifST@mp
+-\newdimen\ST@wd
+-\newskip\ST@rightskip
+-\newskip\ST@leftskip
+-\newskip\ST@parfillskip
+-\long\def\ST@caption#1[#2]#3{\par%
+-  \addcontentsline{\csname ext@#1\endcsname}{#1}%
+-                  {\protect\numberline{%
+-                      \csname the#1\endcsname}{\ignorespaces #2}}
+-  \begingroup
+-    \@parboxrestore
+-    \normalsize
+-    \if@topcaption \vskip -10\p@ \fi
+-    \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par
+-    \if@topcaption \vskip 10\p@ \fi
+-  \endgroup}
+-\newcommand\tablehead[1]{%
+-  \gdef\@tablehead{%
+-  \noalign{%
+-      \global\let\@savcr=\\
+-      \global\let\\=\org@tabularcr}%
+-    #1%
+-    \noalign{\global\let\\=\@savcr}}}
+-\tablehead{}
+-\newcommand\tablefirsthead[1]{\gdef\@table@first@head{#1}}
+-\newcommand\tabletail[1]{%
+-  \gdef\@tabletail{%
+-    \noalign{%
+-      \global\let\@savcr=\\
+-      \global\let\\=\org@tabularcr}%
+-    #1%
+-    \noalign{\global\let\\=\@savcr}}}
+-\tabletail{}
+-\newcommand\tablelasttail[1]{\gdef\@table@last@tail{#1}}
+-\newcommand\sttraceon{\c@tracingst5\relax}
+-\newcommand\sttraceoff{\c@tracingst\z@}
+-\newcommand\ST@trace[2]{%
+-  \ifnum\c@tracingst>#1\relax
+-    \GenericWarning
+-      {(supertabular)\@spaces\@spaces}
+-      {Package supertabular: #2}%
+-  \fi
+-  }
+-\newdimen\ST@pageleft
+-\newcommand*\shrinkheight[1]{%
+-  \noalign{\global\advance\ST@pageleft-#1\relax}}
+-\newcommand*\setSTheight[1]{%
+-  \noalign{\global\ST@pageleft=#1\relax}}
+-\newdimen\ST@headht
+-\newdimen\ST@tailht
+-\newdimen\ST@pagesofar
+-\newdimen\ST@pboxht
+-\newdimen\ST@lineht
+-\newdimen\ST@stretchht
+-\newdimen\ST@prevht
+-\newdimen\ST@toadd
+-\newdimen\ST@dimen
+-\newbox\ST@pbox
+-\def\ST@tabularcr{%
+-  {\ifnum0=`}\fi
+-  \@ifstar{\ST@xtabularcr}{\ST@xtabularcr}}
+-\def\ST@xtabularcr{%
+-  \@ifnextchar[%]
+-    {\ST@argtabularcr}%
+-    {\ifnum0=`{\fi}\cr\ST@cr}}
+-\def\ST@argtabularcr[#1]{%
+-  \ifnum0=`{\fi}%
+-  \ifdim #1>\z@
+-    \unskip\ST@xargarraycr{#1}
+-  \else
+-    \ST@yargarraycr{#1}%
+-  \fi}
+-\def\ST@xargarraycr#1{%
+-  \@tempdima #1\advance\@tempdima \dp \@arstrutbox
+-  \vrule \@height\z@ \@depth\@tempdima \@width\z@ \cr
+-  \noalign{\global\ST@toadd=#1}\ST@cr}
+-\def\ST@yargarraycr#1{%
+-  \cr\noalign{\vskip #1\global\ST@toadd=#1}\ST@cr}
+-\def\ST@startpbox#1{%
+-  \setbox\ST@pbox\vtop\bgroup\hsize#1\@arrayparboxrestore}
+-\def\ST@astartpbox#1{%
+-  \bgroup\hsize#1%
+-  \setbox\ST@pbox\vtop\bgroup\hsize#1\@arrayparboxrestore}
+-\def\ST@endpbox{%
+-  \@finalstrut\@arstrutbox\par\egroup
+-  \ST@dimen=\ht\ST@pbox
+-  \advance\ST@dimen by \dp\ST@pbox
+-  \ifnum\ST@pboxht<\ST@dimen
+-    \global\ST@pboxht=\ST@dimen
+-  \fi
+-  \ST@dimen=\z@
+-  \box\ST@pbox\hfil}
+-\def\ST@aendpbox{%
+-  \@finalstrut\@arstrutbox\par\egroup
+-  \ST@dimen=\ht\ST@pbox
+-  \advance\ST@dimen by \dp\ST@pbox
+-  \ifnum\ST@pboxht<\ST@dimen
+-    \global\ST@pboxht=\ST@dimen
+-  \fi
+-  \ST@dimen=\z@
+-  \unvbox\ST@pbox\egroup\hfil}
+-\def\estimate@lineht{%
+-  \ST@lineht=\arraystretch \baslineskp
+-  \global\advance\ST@lineht by 1\p@
+-  \ST@stretchht\ST@lineht\advance\ST@stretchht-\baslineskp
+-  \ifdim\ST@stretchht<\z@\ST@stretchht\z@\fi
+-  \ST@trace\tw@{Average line height: \the\ST@lineht}%
+-  \ST@trace\tw@{Stretched line height: \the\ST@stretchht}%
+-  }
+-\def\@calfirstpageht{%
+-  \ST@trace\tw@{Calculating height of tabular on first page}%
+-  \global\ST@pagesofar\pagetotal
+-  \global\ST@pageleft\@colroom
+-  \ST@trace\tw@{Height of text = \the\pagetotal; \MessageBreak
+-                Height of page = \the\ST@pageleft}%
+-  \if@twocolumn
+-    \ST@trace\tw@{two column mode}%
+-    \if@firstcolumn
+-     \ST@trace\tw@{First column}%
+-      \ifnum\ST@pagesofar > \ST@pageleft
+-        \global\ST@pageleft=2\ST@pageleft
+-        \ifnum\ST@pagesofar > \ST@pageleft
+-          \newpage\@calnextpageht
+-          \ST@trace\tw@{starting new page}%
+-        \else
+-          \ST@trace\tw@{Second column}%
+-          \global\advance\ST@pageleft -\ST@pagesofar
+-          \global\advance\ST@pageleft -\@colroom
+-        \fi
+-      \else
+-        \global\advance\ST@pageleft by -\ST@pagesofar
+-        \global\ST@pagesofar\z@
+-      \fi
+-    \else
+-      \ST@trace\tw@{Second column}
+-      \ifnum\ST@pagesofar > \ST@pageleft
+-        \ST@trace\tw@{starting new page}%
+-        \newpage\@calnextpageht
+-      \else
+-        \global\advance\ST@pageleft by -\ST@pagesofar
+-        \global\ST@pagesofar\z@
+-      \fi
+-    \fi
+-  \else
+-    \ST@trace\tw@{one column mode}%
+-    \ifnum\ST@pagesofar > \ST@pageleft
+-      \ST@trace\tw@{starting new page}%
+-      \newpage\@calnextpageht
+-    \else
+-      \global\advance\ST@pageleft by -\ST@pagesofar
+-      \global\ST@pagesofar\z@
+-    \fi
+-  \fi
+-  \ST@trace\tw@{Available height: \the\ST@pageleft}%
+-  \ifx\@@tablehead\@empty
+-    \ST@headht=\z@
+-  \else
+-    \setbox\@tempboxa=\vbox{\@arrayparboxrestore
+-      \ST@restore
+-      \expandafter\tabular\expandafter{\ST@tableformat}%
+-      \@@tablehead\endtabular}%
+-    \ST@headht=\ht\@tempboxa\advance\ST@headht\dp\@tempboxa
+-  \fi
+-  \ST@trace\tw@{Height of head: \the\ST@headht}%
+-  \ifx\@tabletail\@empty
+-    \ST@tailht=\z@
+-  \else
+-    \setbox\@tempboxa=\vbox{\@arrayparboxrestore
+-      \ST@restore
+-      \expandafter\tabular\expandafter{\ST@tableformat}
+-        \@tabletail\endtabular}
+-    \ST@tailht=\ht\@tempboxa\advance\ST@tailht\dp\@tempboxa
+-  \fi
+-  \advance\ST@tailht by \ST@lineht
+-  \ST@trace\tw@{Height of tail: \the\ST@tailht}%
+-  \ST@trace\tw@{Maximum height of tabular: \the\ST@pageleft}%
+-  \@tempdima\ST@headht
+-  \advance\@tempdima\ST@lineht
+-  \advance\@tempdima\ST@tailht
+-  \ST@trace\tw@{Minimum height of tabular: \the\@tempdima}%
+-  \ifnum\@tempdima>\ST@pageleft
+-    \ST@trace\tw@{starting new page}%
+-    \newpage\@calnextpageht
+-  \fi
+-}
+-\def\@calnextpageht{%
+-  \ST@trace\tw@{Calculating height of tabular on next page}%
+-  \global\ST@pageleft\@colroom
+-  \global\ST@pagesofar=\z@
+-  \ST@trace\tw@{Maximum height of tabular: \the\ST@pageleft}%
+-  }
+-\def\x@supertabular{%
+-  \let\org@tabular\tabular
+-  \let\tabular\inner@tabular
+-  \expandafter\let
+-    \csname org@tabular*\expandafter\endcsname
+-    \csname tabular*\endcsname
+-  \expandafter\let\csname tabular*\expandafter\endcsname
+-    \csname inner@tabular*\endcsname
+-  \if@topcaption \@process@tablecaption \fi
+-  \global\let\@oldcr=\\
+-  \def\baslineskp{\baselineskip}%
+-  \ifx\undefined\@classix
+-    \let\org@tabularcr\@tabularcr
+-    \let\@tabularcr\ST@tabularcr
+-    \let\org@startpbox=\@startpbox
+-    \let\org@endpbox=\@endpbox
+-    \let\@@startpbox=\ST@startpbox
+-    \let\@@endpbox=\ST@endpbox
+-  \else
+-    \let\org@tabularcr\@arraycr
+-    \let\@arraycr\ST@tabularcr
+-    \let\org@startpbox=\@startpbox
+-    \let\org@endpbox=\@endpbox
+-    \let\@startpbox=\ST@astartpbox
+-    \let\@endpbox=\ST@aendpbox
+-  \fi
+-  \ifx\@table@first@head\undefined
+-    \let\@@tablehead=\@tablehead
+-  \else
+-    \let\@@tablehead=\@table@first@head
+-  \fi
+-  \let\ST@skippage\ST@skipfirstpart
+-  \estimate@lineht
+-  \@calfirstpageht
+-  \noindent
+-  }
+-\def\supertabular{%
+-  \@ifnextchar[{\@supertabular}%]
+-               {\@supertabular[]}}
+-\def\@supertabular[#1]#2{%
+-  \def\ST@tableformat{#2}%
+-  \ST@trace\tw@{Starting a new supertabular}%
+-  \global\ST@starfalse
+-  \global\ST@mpfalse
+-  \x@supertabular
+-  \expandafter\org@tabular\expandafter{\ST@tableformat}%
+-  \@@tablehead}
+-\@namedef{supertabular*}#1{%
+-  \@ifnextchar[{\@nameuse{@supertabular*}{#1}}%
+-               {\@nameuse{@supertabular*}{#1}[]}%]
+-  }
+-\@namedef{@supertabular*}#1[#2]#3{%
+-  \ST@trace\tw@{Starting a new supertabular*}%
+-  \def\ST@tableformat{#3}%
+-  \ST@wd=#1\relax
+-  \global\ST@startrue
+-  \global\ST@mpfalse
+-  \x@supertabular
+-  \expandafter\csname org@tabular*\expandafter\endcsname
+-  \expandafter{\expandafter\ST@wd\expandafter}%
+-  \expandafter{\ST@tableformat}%
+-  \@@tablehead}%
+-\def\mpsupertabular{%
+-  \@ifnextchar[{\@mpsupertabular}%]
+-               {\@mpsupertabular[]}}
+-\def\@mpsupertabular[#1]#2{%
+-  \def\ST@tableformat{#2}%
+-  \ST@trace\tw@{Starting a new mpsupertabular}%
+-  \global\ST@starfalse
+-  \global\ST@mptrue
+-  \ST@rightskip \rightskip
+-  \ST@leftskip \leftskip
+-  \ST@parfillskip \parfillskip
+-  \x@supertabular
+-  \minipage{\columnwidth}%
+-  \parfillskip\ST@parfillskip
+-  \rightskip \ST@rightskip
+-  \leftskip \ST@leftskip
+-  \noindent\expandafter\org@tabular\expandafter{\ST@tableformat}%
+-  \@@tablehead}
+-\@namedef{mpsupertabular*}#1{%
+-  \@ifnextchar[{\@nameuse{@mpsupertabular*}{#1}}%
+-               {\@nameuse{@mpsupertabular*}{#1}[]}%]
+-  }
+-\@namedef{@mpsupertabular*}#1[#2]#3{%
+-  \ST@trace\tw@{Starting a new mpsupertabular*}%
+-  \def\ST@tableformat{#3}%
+-  \ST@wd=#1\relax
+-  \global\ST@startrue
+-  \global\ST@mptrue
+-  \ST@rightskip \rightskip
+-  \ST@leftskip \leftskip
+-  \ST@parfillskip \parfillskip
+-  \x@supertabular
+-  \minipage{\columnwidth}%
+-  \parfillskip\ST@parfillskip
+-  \rightskip \ST@rightskip
+-  \leftskip \ST@leftskip
+-  \noindent\expandafter\csname org@tabular*\expandafter\endcsname
+-  \expandafter{\expandafter\ST@wd\expandafter}%
+-  \expandafter{\ST@tableformat}%
+-  \@@tablehead}%
+-\def\endsupertabular{%
+-  \ifx\@table@last@tail\undefined
+-    \@tabletail
+-  \else
+-    \@table@last@tail
+-  \fi
+-  \csname endtabular\ifST@star*\fi\endcsname
+-  \ST@restore
+-  \if@topcaption
+-  \else
+-    \@process@tablecaption
+-    \@topcaptiontrue
+-  \fi
+-  \global\let\\\@oldcr
+-  \global\let\@process@tablecaption\relax
+-  \ST@trace\tw@{Ended a supertabular\ifST@star*\fi}%
+-  }
+-\expandafter\let\csname endsupertabular*\endcsname\endsupertabular
+-\def\endmpsupertabular{%
+-  \ifx\@table@last@tail\undefined
+-    \@tabletail
+-  \else
+-    \@table@last@tail
+-  \fi
+-  \csname endtabular\ifST@star*\fi\endcsname
+-  \endminipage
+-  \ST@restore
+-  \if@topcaption
+-  \else
+-    \@process@tablecaption
+-    \@topcaptiontrue
+-  \fi
+-  \global\let\\\@oldcr
+-  \global\let\@process@tablecaption\relax
+-  \ST@trace\tw@{Ended a mpsupertabular\ifST@star*\fi}%
+-  }
+-\expandafter\let\csname endmpsupertabular*\endcsname\endmpsupertabular
+-\def\ST@restore{%
+-  \ifx\undefined\@classix
+-    \let\@tabularcr\org@tabularcr
+-  \else
+-    \let\@arraycr\org@tabularcr
+-  \fi
+-  \let\@startpbox\org@startpbox
+-  \let\@endpbox\org@endpbox
+-  }
+-\def\inner@tabular{%
+-  \ST@restore
+-  \let\\\@oldcr
+-  \noindent
+-  \org@tabular}
+-\@namedef{inner@tabular*}{%
+-  \ST@restore
+-  \let\\\@oldcr
+-  \noindent
+-  \csname org@tabular*\endcsname}
+-\def\ST@cr{%
+-  \noalign{%
+-    \ifnum\ST@pboxht<\ST@lineht
+-      \global\advance\ST@pageleft -\ST@lineht
+-      \global\ST@prevht\ST@lineht
+-    \else
+-     \ST@trace\thr@@{Added par box with height \the\ST@pboxht}%
+-      \global\advance\ST@pageleft -\ST@pboxht
+-      \global\advance\ST@pageleft -0.1\ST@pboxht
+-      \global\advance\ST@pageleft -\ST@stretchht
+-      \global\ST@prevht\ST@pboxht
+-      \global\ST@pboxht\z@
+-    \fi
+-    \global\advance\ST@pageleft -\ST@toadd
+-    \global\ST@toadd=\z@
+-    \ST@trace\thr@@{Space left for tabular: \the\ST@pageleft}%
+-  }
+-  \noalign{\global\let\ST@next\@empty}%
+-  \ifnum\ST@pageleft<\z@
+-    \ST@skippage
+-  \else
+-    \noalign{\global\@tempdima\ST@tailht
+-      \global\advance\@tempdima\ST@prevht
+-    \ifST@mp
+-      \ifvoid\@mpfootins\else
+-        \global\advance\@tempdima\ht\@mpfootins
+-        \global\advance\@tempdima 3pt
+-      \fi
+-    \fi}
+-    \ifnum\ST@pageleft<\@tempdima
+-      \ST@newpage
+-    \fi
+-  \fi
+-  \ST@next}
+-\def\ST@skipfirstpart{%
+-  \noalign{%
+-    \ST@trace\tw@{Tabular too high, moving to next page}%
+-    \global\advance\ST@pageleft\pagetotal
+-    \global\ST@pagesofar\z@
+-    \newpage
+-    \global\let\ST@skippage\ST@newpage
+-    }}
+-\def\ST@newpage{%
+-  \noalign{\ST@trace\tw@{Starting new page, writing tail}}%
+-  \@tabletail
+-  \ifST@star
+-    \csname endtabular*\endcsname
+-  \else
+-    \endtabular
+-  \fi
+-  \ifST@mp
+-    \endminipage
+-  \fi
+-  \global\let\ST@skippage\ST@newpage
+-  \newpage\@calnextpageht
+-  \let\ST@next\@tablehead
+-  \ST@trace\tw@{writing head}%
+-  \ifST@mp
+-    \noindent\minipage{\columnwidth}%
+-    \parfillskip\ST@parfillskip
+-    \rightskip \ST@rightskip
+-    \leftskip \ST@leftskip
+-  \fi
+-  \noindent
+-  \ifST@star
+-    \expandafter\csname org@tabular*\expandafter\endcsname
+-    \expandafter{\expandafter\ST@wd\expandafter}%
+-    \expandafter{\ST@tableformat}%
+-  \else
+-    \expandafter\org@tabular\expandafter{\ST@tableformat}%
+-  \fi}
+-\endinput
+-%%
+-%% End of file `supertabular.sty'.
+diff --git a/scipy/linalg/src/id_dist/src/dfft.f b/scipy/linalg/src/id_dist/src/dfft.f
+deleted file mode 100644
+index b1b1b3206..000000000
+--- a/scipy/linalg/src/id_dist/src/dfft.f
++++ /dev/null
+@@ -1,3014 +0,0 @@
+-C
+-C                       FFTPACK
+-C
+-C * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+-C
+-C                   VERSION 4  APRIL 1985
+-C
+-C      A PACKAGE OF FORTRAN SUBPROGRAMS FOR THE FAST FOURIER
+-C       TRANSFORM OF PERIODIC AND OTHER SYMMETRIC SEQUENCES
+-C
+-C                          BY
+-C
+-C                   PAUL N SWARZTRAUBER
+-C
+-C   NATIONAL CENTER FOR ATMOSPHERIC RESEARCH  BOULDER,COLORADO 80307
+-C
+-C    WHICH IS SPONSORED BY THE NATIONAL SCIENCE FOUNDATION
+-C
+-C * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+-C
+-C
+-C THIS PACKAGE CONSISTS OF PROGRAMS WHICH PERFORM FAST FOURIER
+-C TRANSFORMS FOR BOTH COMPLEX AND REAL PERIODIC SEQUENCES AND
+-C CERTAIN OTHER SYMMETRIC SEQUENCES THAT ARE LISTED BELOW.
+-C
+-C 1.   DFFTI     INITIALIZE  DFFTF AND DFFTB
+-C 2.   DFFTF     FORWARD TRANSFORM OF A REAL PERIODIC SEQUENCE
+-C 3.   DFFTB     BACKWARD TRANSFORM OF A REAL COEFFICIENT ARRAY
+-C
+-C 4.   DZFFTI    INITIALIZE DZFFTF AND DZFFTB
+-C 5.   DZFFTF    A SIMPLIFIED REAL PERIODIC FORWARD TRANSFORM
+-C 6.   DZFFTB    A SIMPLIFIED REAL PERIODIC BACKWARD TRANSFORM
+-C
+-C 7.   DSINTI     INITIALIZE DSINT
+-C 8.   DSINT      SINE TRANSFORM OF A REAL ODD SEQUENCE
+-C
+-C 9.   DCOSTI     INITIALIZE DCOST
+-C 10.  DCOST      COSINE TRANSFORM OF A REAL EVEN SEQUENCE
+-C
+-C 11.  DSINQI     INITIALIZE DSINQF AND DSINQB
+-C 12.  DSINQF     FORWARD SINE TRANSFORM WITH ODD WAVE NUMBERS
+-C 13.  DSINQB     UNNORMALIZED INVERSE OF DSINQF
+-C
+-C 14.  DCOSQI     INITIALIZE DCOSQF AND DCOSQB
+-C 15.  DCOSQF     FORWARD COSINE TRANSFORM WITH ODD WAVE NUMBERS
+-C 16.  DCOSQB     UNNORMALIZED INVERSE OF DCOSQF
+-C
+-C 17.  ZFFTI     INITIALIZE ZFFTF AND ZFFTB
+-C 18.  ZFFTF     FORWARD TRANSFORM OF A COMPLEX PERIODIC SEQUENCE
+-C 19.  ZFFTB     UNNORMALIZED INVERSE OF ZFFTF
+-C
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DFFTI(N,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DFFTI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
+-C BOTH DFFTF AND DFFTB. THE PRIME FACTORIZATION OF N TOGETHER WITH
+-C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
+-C STORED IN WSAVE.
+-C
+-C INPUT PARAMETER
+-C
+-C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED.
+-C
+-C OUTPUT PARAMETER
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 2*N+15.
+-C         THE SAME WORK ARRAY CAN BE USED FOR BOTH DFFTF AND DFFTB
+-C         AS LONG AS N REMAINS UNCHANGED. DIFFERENT WSAVE ARRAYS
+-C         ARE REQUIRED FOR DIFFERENT VALUES OF N. THE CONTENTS OF
+-C         WSAVE MUST NOT BE CHANGED BETWEEN CALLS OF DFFTF OR DFFTB.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DFFTF(N,R,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DFFTF COMPUTES THE FOURIER COEFFICIENTS OF A REAL
+-C PERODIC SEQUENCE (FOURIER ANALYSIS). THE TRANSFORM IS DEFINED
+-C BELOW AT OUTPUT PARAMETER R.
+-C
+-C INPUT PARAMETERS
+-C
+-C N       THE LENGTH OF THE ARRAY R TO BE TRANSFORMED.  THE METHOD
+-C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
+-C         N MAY CHANGE SO LONG AS DIFFERENT WORK ARRAYS ARE PROVIDED
+-C
+-C R       A REAL ARRAY OF LENGTH N WHICH CONTAINS THE SEQUENCE
+-C         TO BE TRANSFORMED
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 2*N+15.
+-C         IN THE PROGRAM THAT CALLS DFFTF. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE DFFTI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C         THE SAME WSAVE ARRAY CAN BE USED BY DFFTF AND DFFTB.
+-C
+-C
+-C OUTPUT PARAMETERS
+-C
+-C R       R(1) = THE SUM FROM I=1 TO I=N OF R(I)
+-C
+-C         IF N IS EVEN SET L =N/2   , IF N IS ODD SET L = (N+1)/2
+-C
+-C           THEN FOR K = 2,...,L
+-C
+-C              R(2*K-2) = THE SUM FROM I = 1 TO I = N OF
+-C
+-C                   R(I)*COS((K-1)*(I-1)*2*PI/N)
+-C
+-C              R(2*K-1) = THE SUM FROM I = 1 TO I = N OF
+-C
+-C                  -R(I)*SIN((K-1)*(I-1)*2*PI/N)
+-C
+-C         IF N IS EVEN
+-C
+-C              R(N) = THE SUM FROM I = 1 TO I = N OF
+-C
+-C                   (-1)**(I-1)*R(I)
+-C
+-C  *****  NOTE
+-C              THIS TRANSFORM IS UNNORMALIZED SINCE A CALL OF DFFTF
+-C              FOLLOWED BY A CALL OF DFFTB WILL MULTIPLY THE INPUT
+-C              SEQUENCE BY N.
+-C
+-C WSAVE   CONTAINS RESULTS WHICH MUST NOT BE DESTROYED BETWEEN
+-C         CALLS OF DFFTF OR DFFTB.
+-C
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DFFTB(N,R,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DFFTB COMPUTES THE REAL PERODIC SEQUENCE FROM ITS
+-C FOURIER COEFFICIENTS (FOURIER SYNTHESIS). THE TRANSFORM IS DEFINED
+-C BELOW AT OUTPUT PARAMETER R.
+-C
+-C INPUT PARAMETERS
+-C
+-C N       THE LENGTH OF THE ARRAY R TO BE TRANSFORMED.  THE METHOD
+-C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
+-C         N MAY CHANGE SO LONG AS DIFFERENT WORK ARRAYS ARE PROVIDED
+-C
+-C R       A REAL ARRAY OF LENGTH N WHICH CONTAINS THE SEQUENCE
+-C         TO BE TRANSFORMED
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 2*N+15.
+-C         IN THE PROGRAM THAT CALLS DFFTB. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE DFFTI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C         THE SAME WSAVE ARRAY CAN BE USED BY DFFTF AND DFFTB.
+-C
+-C
+-C OUTPUT PARAMETERS
+-C
+-C R       FOR N EVEN AND FOR I = 1,...,N
+-C
+-C              R(I) = R(1)+(-1)**(I-1)*R(N)
+-C
+-C                   PLUS THE SUM FROM K=2 TO K=N/2 OF
+-C
+-C                    2.*R(2*K-2)*COS((K-1)*(I-1)*2*PI/N)
+-C
+-C                   -2.*R(2*K-1)*SIN((K-1)*(I-1)*2*PI/N)
+-C
+-C         FOR N ODD AND FOR I = 1,...,N
+-C
+-C              R(I) = R(1) PLUS THE SUM FROM K=2 TO K=(N+1)/2 OF
+-C
+-C                   2.*R(2*K-2)*COS((K-1)*(I-1)*2*PI/N)
+-C
+-C                  -2.*R(2*K-1)*SIN((K-1)*(I-1)*2*PI/N)
+-C
+-C  *****  NOTE
+-C              THIS TRANSFORM IS UNNORMALIZED SINCE A CALL OF DFFTF
+-C              FOLLOWED BY A CALL OF DFFTB WILL MULTIPLY THE INPUT
+-C              SEQUENCE BY N.
+-C
+-C WSAVE   CONTAINS RESULTS WHICH MUST NOT BE DESTROYED BETWEEN
+-C         CALLS OF DFFTB OR DFFTF.
+-C
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DZFFTI(N,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DZFFTI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
+-C BOTH DZFFTF AND DZFFTB. THE PRIME FACTORIZATION OF N TOGETHER WITH
+-C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
+-C STORED IN WSAVE.
+-C
+-C INPUT PARAMETER
+-C
+-C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED.
+-C
+-C OUTPUT PARAMETER
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
+-C         THE SAME WORK ARRAY CAN BE USED FOR BOTH DZFFTF AND DZFFTB
+-C         AS LONG AS N REMAINS UNCHANGED. DIFFERENT WSAVE ARRAYS
+-C         ARE REQUIRED FOR DIFFERENT VALUES OF N.
+-C
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DZFFTF(N,R,AZERO,A,B,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DZFFTF COMPUTES THE FOURIER COEFFICIENTS OF A REAL
+-C PERODIC SEQUENCE (FOURIER ANALYSIS). THE TRANSFORM IS DEFINED
+-C BELOW AT OUTPUT PARAMETERS AZERO,A AND B. DZFFTF IS A SIMPLIFIED
+-C BUT SLOWER VERSION OF DFFTF.
+-C
+-C INPUT PARAMETERS
+-C
+-C N       THE LENGTH OF THE ARRAY R TO BE TRANSFORMED.  THE METHOD
+-C         IS MUST EFFICIENT WHEN N IS THE PRODUCT OF SMALL PRIMES.
+-C
+-C R       A REAL ARRAY OF LENGTH N WHICH CONTAINS THE SEQUENCE
+-C         TO BE TRANSFORMED. R IS NOT DESTROYED.
+-C
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
+-C         IN THE PROGRAM THAT CALLS DZFFTF. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE DZFFTI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C         THE SAME WSAVE ARRAY CAN BE USED BY DZFFTF AND DZFFTB.
+-C
+-C OUTPUT PARAMETERS
+-C
+-C AZERO   THE SUM FROM I=1 TO I=N OF R(I)/N
+-C
+-C A,B     FOR N EVEN B(N/2)=0. AND A(N/2) IS THE SUM FROM I=1 TO
+-C         I=N OF (-1)**(I-1)*R(I)/N
+-C
+-C         FOR N EVEN DEFINE KMAX=N/2-1
+-C         FOR N ODD  DEFINE KMAX=(N-1)/2
+-C
+-C         THEN FOR  K=1,...,KMAX
+-C
+-C              A(K) EQUALS THE SUM FROM I=1 TO I=N OF
+-C
+-C                   2./N*R(I)*COS(K*(I-1)*2*PI/N)
+-C
+-C              B(K) EQUALS THE SUM FROM I=1 TO I=N OF
+-C
+-C                   2./N*R(I)*SIN(K*(I-1)*2*PI/N)
+-C
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DZFFTB(N,R,AZERO,A,B,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DZFFTB COMPUTES A REAL PERODIC SEQUENCE FROM ITS
+-C FOURIER COEFFICIENTS (FOURIER SYNTHESIS). THE TRANSFORM IS
+-C DEFINED BELOW AT OUTPUT PARAMETER R. DZFFTB IS A SIMPLIFIED
+-C BUT SLOWER VERSION OF DFFTB.
+-C
+-C INPUT PARAMETERS
+-C
+-C N       THE LENGTH OF THE OUTPUT ARRAY R.  THE METHOD IS MOST
+-C         EFFICIENT WHEN N IS THE PRODUCT OF SMALL PRIMES.
+-C
+-C AZERO   THE CONSTANT FOURIER COEFFICIENT
+-C
+-C A,B     ARRAYS WHICH CONTAIN THE REMAINING FOURIER COEFFICIENTS
+-C         THESE ARRAYS ARE NOT DESTROYED.
+-C
+-C         THE LENGTH OF THESE ARRAYS DEPENDS ON WHETHER N IS EVEN OR
+-C         ODD.
+-C
+-C         IF N IS EVEN N/2    LOCATIONS ARE REQUIRED
+-C         IF N IS ODD (N-1)/2 LOCATIONS ARE REQUIRED
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
+-C         IN THE PROGRAM THAT CALLS DZFFTB. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE DZFFTI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C         THE SAME WSAVE ARRAY CAN BE USED BY DZFFTF AND DZFFTB.
+-C
+-C
+-C OUTPUT PARAMETERS
+-C
+-C R       IF N IS EVEN DEFINE KMAX=N/2
+-C         IF N IS ODD  DEFINE KMAX=(N-1)/2
+-C
+-C         THEN FOR I=1,...,N
+-C
+-C              R(I)=AZERO PLUS THE SUM FROM K=1 TO K=KMAX OF
+-C
+-C              A(K)*COS(K*(I-1)*2*PI/N)+B(K)*SIN(K*(I-1)*2*PI/N)
+-C
+-C ********************* COMPLEX NOTATION **************************
+-C
+-C         FOR J=1,...,N
+-C
+-C         R(J) EQUALS THE SUM FROM K=-KMAX TO K=KMAX OF
+-C
+-C              C(K)*EXP(I*K*(J-1)*2*PI/N)
+-C
+-C         WHERE
+-C
+-C              C(K) = .5*CMPLX(A(K),-B(K))   FOR K=1,...,KMAX
+-C
+-C              C(-K) = CONJG(C(K))
+-C
+-C              C(0) = AZERO
+-C
+-C                   AND I=SQRT(-1)
+-C
+-C *************** AMPLITUDE - PHASE NOTATION ***********************
+-C
+-C         FOR I=1,...,N
+-C
+-C         R(I) EQUALS AZERO PLUS THE SUM FROM K=1 TO K=KMAX OF
+-C
+-C              ALPHA(K)*COS(K*(I-1)*2*PI/N+BETA(K))
+-C
+-C         WHERE
+-C
+-C              ALPHA(K) = SQRT(A(K)*A(K)+B(K)*B(K))
+-C
+-C              COS(BETA(K))=A(K)/ALPHA(K)
+-C
+-C              SIN(BETA(K))=-B(K)/ALPHA(K)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DSINTI(N,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DSINTI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
+-C SUBROUTINE DSINT. THE PRIME FACTORIZATION OF N TOGETHER WITH
+-C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
+-C STORED IN WSAVE.
+-C
+-C INPUT PARAMETER
+-C
+-C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED.  THE METHOD
+-C         IS MOST EFFICIENT WHEN N+1 IS A PRODUCT OF SMALL PRIMES.
+-C
+-C OUTPUT PARAMETER
+-C
+-C WSAVE   A WORK ARRAY WITH AT LEAST INT(2.5*N+15) LOCATIONS.
+-C         DIFFERENT WSAVE ARRAYS ARE REQUIRED FOR DIFFERENT VALUES
+-C         OF N. THE CONTENTS OF WSAVE MUST NOT BE CHANGED BETWEEN
+-C         CALLS OF DSINT.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DSINT(N,X,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DSINT COMPUTES THE DISCRETE FOURIER SINE TRANSFORM
+-C OF AN ODD SEQUENCE X(I). THE TRANSFORM IS DEFINED BELOW AT
+-C OUTPUT PARAMETER X.
+-C
+-C DSINT IS THE UNNORMALIZED INVERSE OF ITSELF SINCE A CALL OF DSINT
+-C FOLLOWED BY ANOTHER CALL OF DSINT WILL MULTIPLY THE INPUT SEQUENCE
+-C X BY 2*(N+1).
+-C
+-C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DSINT MUST BE
+-C INITIALIZED BY CALLING SUBROUTINE DSINTI(N,WSAVE).
+-C
+-C INPUT PARAMETERS
+-C
+-C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED.  THE METHOD
+-C         IS MOST EFFICIENT WHEN N+1 IS THE PRODUCT OF SMALL PRIMES.
+-C
+-C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
+-C
+-C
+-C WSAVE   A WORK ARRAY WITH DIMENSION AT LEAST INT(2.5*N+15)
+-C         IN THE PROGRAM THAT CALLS DSINT. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE DSINTI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C
+-C OUTPUT PARAMETERS
+-C
+-C X       FOR I=1,...,N
+-C
+-C              X(I)= THE SUM FROM K=1 TO K=N
+-C
+-C                   2*X(K)*SIN(K*I*PI/(N+1))
+-C
+-C              A CALL OF DSINT FOLLOWED BY ANOTHER CALL OF
+-C              DSINT WILL MULTIPLY THE SEQUENCE X BY 2*(N+1).
+-C              HENCE DSINT IS THE UNNORMALIZED INVERSE
+-C              OF ITSELF.
+-C
+-C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT BE
+-C         DESTROYED BETWEEN CALLS OF DSINT.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DCOSTI(N,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DCOSTI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
+-C SUBROUTINE DCOST. THE PRIME FACTORIZATION OF N TOGETHER WITH
+-C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
+-C STORED IN WSAVE.
+-C
+-C INPUT PARAMETER
+-C
+-C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED.  THE METHOD
+-C         IS MOST EFFICIENT WHEN N-1 IS A PRODUCT OF SMALL PRIMES.
+-C
+-C OUTPUT PARAMETER
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
+-C         DIFFERENT WSAVE ARRAYS ARE REQUIRED FOR DIFFERENT VALUES
+-C         OF N. THE CONTENTS OF WSAVE MUST NOT BE CHANGED BETWEEN
+-C         CALLS OF DCOST.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DCOST(N,X,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DCOST COMPUTES THE DISCRETE FOURIER COSINE TRANSFORM
+-C OF AN EVEN SEQUENCE X(I). THE TRANSFORM IS DEFINED BELOW AT OUTPUT
+-C PARAMETER X.
+-C
+-C DCOST IS THE UNNORMALIZED INVERSE OF ITSELF SINCE A CALL OF DCOST
+-C FOLLOWED BY ANOTHER CALL OF DCOST WILL MULTIPLY THE INPUT SEQUENCE
+-C X BY 2*(N-1). THE TRANSFORM IS DEFINED BELOW AT OUTPUT PARAMETER X
+-C
+-C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DCOST MUST BE
+-C INITIALIZED BY CALLING SUBROUTINE DCOSTI(N,WSAVE).
+-C
+-C INPUT PARAMETERS
+-C
+-C N       THE LENGTH OF THE SEQUENCE X. N MUST BE GREATER THAN 1.
+-C         THE METHOD IS MOST EFFICIENT WHEN N-1 IS A PRODUCT OF
+-C         SMALL PRIMES.
+-C
+-C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15
+-C         IN THE PROGRAM THAT CALLS DCOST. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE DCOSTI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C
+-C OUTPUT PARAMETERS
+-C
+-C X       FOR I=1,...,N
+-C
+-C             X(I) = X(1)+(-1)**(I-1)*X(N)
+-C
+-C              + THE SUM FROM K=2 TO K=N-1
+-C
+-C                  2*X(K)*COS((K-1)*(I-1)*PI/(N-1))
+-C
+-C              A CALL OF DCOST FOLLOWED BY ANOTHER CALL OF
+-C              DCOST WILL MULTIPLY THE SEQUENCE X BY 2*(N-1)
+-C              HENCE DCOST IS THE UNNORMALIZED INVERSE
+-C              OF ITSELF.
+-C
+-C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT BE
+-C         DESTROYED BETWEEN CALLS OF DCOST.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DSINQI(N,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DSINQI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
+-C BOTH DSINQF AND DSINQB. THE PRIME FACTORIZATION OF N TOGETHER WITH
+-C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
+-C STORED IN WSAVE.
+-C
+-C INPUT PARAMETER
+-C
+-C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED. THE METHOD
+-C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
+-C
+-C OUTPUT PARAMETER
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
+-C         THE SAME WORK ARRAY CAN BE USED FOR BOTH DSINQF AND DSINQB
+-C         AS LONG AS N REMAINS UNCHANGED. DIFFERENT WSAVE ARRAYS
+-C         ARE REQUIRED FOR DIFFERENT VALUES OF N. THE CONTENTS OF
+-C         WSAVE MUST NOT BE CHANGED BETWEEN CALLS OF DSINQF OR DSINQB.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DSINQF(N,X,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DSINQF COMPUTES THE FAST FOURIER TRANSFORM OF QUARTER
+-C WAVE DATA. THAT IS , DSINQF COMPUTES THE COEFFICIENTS IN A SINE
+-C SERIES REPRESENTATION WITH ONLY ODD WAVE NUMBERS. THE TRANSFORM
+-C IS DEFINED BELOW AT OUTPUT PARAMETER X.
+-C
+-C DSINQB IS THE UNNORMALIZED INVERSE OF DSINQF SINCE A CALL OF DSINQF
+-C FOLLOWED BY A CALL OF DSINQB WILL MULTIPLY THE INPUT SEQUENCE X
+-C BY 4*N.
+-C
+-C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DSINQF MUST BE
+-C INITIALIZED BY CALLING SUBROUTINE DSINQI(N,WSAVE).
+-C
+-C
+-C INPUT PARAMETERS
+-C
+-C N       THE LENGTH OF THE ARRAY X TO BE TRANSFORMED.  THE METHOD
+-C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
+-C
+-C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
+-C         IN THE PROGRAM THAT CALLS DSINQF. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE DSINQI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C
+-C OUTPUT PARAMETERS
+-C
+-C X       FOR I=1,...,N
+-C
+-C              X(I) = (-1)**(I-1)*X(N)
+-C
+-C                 + THE SUM FROM K=1 TO K=N-1 OF
+-C
+-C                 2*X(K)*SIN((2*I-1)*K*PI/(2*N))
+-C
+-C              A CALL OF DSINQF FOLLOWED BY A CALL OF
+-C              DSINQB WILL MULTIPLY THE SEQUENCE X BY 4*N.
+-C              THEREFORE DSINQB IS THE UNNORMALIZED INVERSE
+-C              OF DSINQF.
+-C
+-C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT
+-C         BE DESTROYED BETWEEN CALLS OF DSINQF OR DSINQB.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DSINQB(N,X,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DSINQB COMPUTES THE FAST FOURIER TRANSFORM OF QUARTER
+-C WAVE DATA. THAT IS , DSINQB COMPUTES A SEQUENCE FROM ITS
+-C REPRESENTATION IN TERMS OF A SINE SERIES WITH ODD WAVE NUMBERS.
+-C THE TRANSFORM IS DEFINED BELOW AT OUTPUT PARAMETER X.
+-C
+-C DSINQF IS THE UNNORMALIZED INVERSE OF DSINQB SINCE A CALL OF DSINQB
+-C FOLLOWED BY A CALL OF DSINQF WILL MULTIPLY THE INPUT SEQUENCE X
+-C BY 4*N.
+-C
+-C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DSINQB MUST BE
+-C INITIALIZED BY CALLING SUBROUTINE DSINQI(N,WSAVE).
+-C
+-C
+-C INPUT PARAMETERS
+-C
+-C N       THE LENGTH OF THE ARRAY X TO BE TRANSFORMED.  THE METHOD
+-C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
+-C
+-C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
+-C         IN THE PROGRAM THAT CALLS DSINQB. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE DSINQI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C
+-C OUTPUT PARAMETERS
+-C
+-C X       FOR I=1,...,N
+-C
+-C              X(I)= THE SUM FROM K=1 TO K=N OF
+-C
+-C                4*X(K)*SIN((2K-1)*I*PI/(2*N))
+-C
+-C              A CALL OF DSINQB FOLLOWED BY A CALL OF
+-C              DSINQF WILL MULTIPLY THE SEQUENCE X BY 4*N.
+-C              THEREFORE DSINQF IS THE UNNORMALIZED INVERSE
+-C              OF DSINQB.
+-C
+-C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT
+-C         BE DESTROYED BETWEEN CALLS OF DSINQB OR DSINQF.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DCOSQI(N,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DCOSQI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
+-C BOTH DCOSQF AND DCOSQB. THE PRIME FACTORIZATION OF N TOGETHER WITH
+-C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
+-C STORED IN WSAVE.
+-C
+-C INPUT PARAMETER
+-C
+-C N       THE LENGTH OF THE ARRAY TO BE TRANSFORMED.  THE METHOD
+-C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
+-C
+-C OUTPUT PARAMETER
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
+-C         THE SAME WORK ARRAY CAN BE USED FOR BOTH DCOSQF AND DCOSQB
+-C         AS LONG AS N REMAINS UNCHANGED. DIFFERENT WSAVE ARRAYS
+-C         ARE REQUIRED FOR DIFFERENT VALUES OF N. THE CONTENTS OF
+-C         WSAVE MUST NOT BE CHANGED BETWEEN CALLS OF DCOSQF OR DCOSQB.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DCOSQF(N,X,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DCOSQF COMPUTES THE FAST FOURIER TRANSFORM OF QUARTER
+-C WAVE DATA. THAT IS , DCOSQF COMPUTES THE COEFFICIENTS IN A COSINE
+-C SERIES REPRESENTATION WITH ONLY ODD WAVE NUMBERS. THE TRANSFORM
+-C IS DEFINED BELOW AT OUTPUT PARAMETER X
+-C
+-C DCOSQF IS THE UNNORMALIZED INVERSE OF DCOSQB SINCE A CALL OF DCOSQF
+-C FOLLOWED BY A CALL OF DCOSQB WILL MULTIPLY THE INPUT SEQUENCE X
+-C BY 4*N.
+-C
+-C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DCOSQF MUST BE
+-C INITIALIZED BY CALLING SUBROUTINE DCOSQI(N,WSAVE).
+-C
+-C
+-C INPUT PARAMETERS
+-C
+-C N       THE LENGTH OF THE ARRAY X TO BE TRANSFORMED.  THE METHOD
+-C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
+-C
+-C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15
+-C         IN THE PROGRAM THAT CALLS DCOSQF. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE DCOSQI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C
+-C OUTPUT PARAMETERS
+-C
+-C X       FOR I=1,...,N
+-C
+-C              X(I) = X(1) PLUS THE SUM FROM K=2 TO K=N OF
+-C
+-C                 2*X(K)*COS((2*I-1)*(K-1)*PI/(2*N))
+-C
+-C              A CALL OF DCOSQF FOLLOWED BY A CALL OF
+-C              DCOSQB WILL MULTIPLY THE SEQUENCE X BY 4*N.
+-C              THEREFORE DCOSQB IS THE UNNORMALIZED INVERSE
+-C              OF DCOSQF.
+-C
+-C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT
+-C         BE DESTROYED BETWEEN CALLS OF DCOSQF OR DCOSQB.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DCOSQB(N,X,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE DCOSQB COMPUTES THE FAST FOURIER TRANSFORM OF QUARTER
+-C WAVE DATA. THAT IS , DCOSQB COMPUTES A SEQUENCE FROM ITS
+-C REPRESENTATION IN TERMS OF A COSINE SERIES WITH ODD WAVE NUMBERS.
+-C THE TRANSFORM IS DEFINED BELOW AT OUTPUT PARAMETER X.
+-C
+-C DCOSQB IS THE UNNORMALIZED INVERSE OF DCOSQF SINCE A CALL OF DCOSQB
+-C FOLLOWED BY A CALL OF DCOSQF WILL MULTIPLY THE INPUT SEQUENCE X
+-C BY 4*N.
+-C
+-C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DCOSQB MUST BE
+-C INITIALIZED BY CALLING SUBROUTINE DCOSQI(N,WSAVE).
+-C
+-C
+-C INPUT PARAMETERS
+-C
+-C N       THE LENGTH OF THE ARRAY X TO BE TRANSFORMED.  THE METHOD
+-C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
+-C
+-C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
+-C
+-C WSAVE   A WORK ARRAY THAT MUST BE DIMENSIONED AT LEAST 3*N+15
+-C         IN THE PROGRAM THAT CALLS DCOSQB. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE DCOSQI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C
+-C OUTPUT PARAMETERS
+-C
+-C X       FOR I=1,...,N
+-C
+-C              X(I)= THE SUM FROM K=1 TO K=N OF
+-C
+-C                4*X(K)*COS((2*K-1)*(I-1)*PI/(2*N))
+-C
+-C              A CALL OF DCOSQB FOLLOWED BY A CALL OF
+-C              DCOSQF WILL MULTIPLY THE SEQUENCE X BY 4*N.
+-C              THEREFORE DCOSQF IS THE UNNORMALIZED INVERSE
+-C              OF DCOSQB.
+-C
+-C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT
+-C         BE DESTROYED BETWEEN CALLS OF DCOSQB OR DCOSQF.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE ZFFTI(N,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE ZFFTI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
+-C BOTH ZFFTF AND ZFFTB. THE PRIME FACTORIZATION OF N TOGETHER WITH
+-C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
+-C STORED IN WSAVE.
+-C
+-C INPUT PARAMETER
+-C
+-C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED
+-C
+-C OUTPUT PARAMETER
+-C
+-C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 4*N+15
+-C         THE SAME WORK ARRAY CAN BE USED FOR BOTH ZFFTF AND ZFFTB
+-C         AS LONG AS N REMAINS UNCHANGED. DIFFERENT WSAVE ARRAYS
+-C         ARE REQUIRED FOR DIFFERENT VALUES OF N. THE CONTENTS OF
+-C         WSAVE MUST NOT BE CHANGED BETWEEN CALLS OF ZFFTF OR ZFFTB.
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE ZFFTF(N,C,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE ZFFTF COMPUTES THE FORWARD COMPLEX DISCRETE FOURIER
+-C TRANSFORM (THE FOURIER ANALYSIS). EQUIVALENTLY , ZFFTF COMPUTES
+-C THE FOURIER COEFFICIENTS OF A COMPLEX PERIODIC SEQUENCE.
+-C THE TRANSFORM IS DEFINED BELOW AT OUTPUT PARAMETER C.
+-C
+-C THE TRANSFORM IS NOT NORMALIZED. TO OBTAIN A NORMALIZED TRANSFORM
+-C THE OUTPUT MUST BE DIVIDED BY N. OTHERWISE A CALL OF ZFFTF
+-C FOLLOWED BY A CALL OF ZFFTB WILL MULTIPLY THE SEQUENCE BY N.
+-C
+-C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE ZFFTF MUST BE
+-C INITIALIZED BY CALLING SUBROUTINE ZFFTI(N,WSAVE).
+-C
+-C INPUT PARAMETERS
+-C
+-C
+-C N      THE LENGTH OF THE COMPLEX SEQUENCE C. THE METHOD IS
+-C        MORE EFFICIENT WHEN N IS THE PRODUCT OF SMALL PRIMES. N
+-C
+-C C      A COMPLEX ARRAY OF LENGTH N WHICH CONTAINS THE SEQUENCE
+-C
+-C WSAVE   A REAL WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 4N+15
+-C         IN THE PROGRAM THAT CALLS ZFFTF. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE ZFFTI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C         THE SAME WSAVE ARRAY CAN BE USED BY ZFFTF AND ZFFTB.
+-C
+-C OUTPUT PARAMETERS
+-C
+-C C      FOR J=1,...,N
+-C
+-C            C(J)=THE SUM FROM K=1,...,N OF
+-C
+-C                  C(K)*EXP(-I*(J-1)*(K-1)*2*PI/N)
+-C
+-C                        WHERE I=SQRT(-1)
+-C
+-C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT BE
+-C         DESTROYED BETWEEN CALLS OF SUBROUTINE ZFFTF OR ZFFTB
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE ZFFTB(N,C,WSAVE)
+-C
+-C ******************************************************************
+-C
+-C SUBROUTINE ZFFTB COMPUTES THE BACKWARD COMPLEX DISCRETE FOURIER
+-C TRANSFORM (THE FOURIER SYNTHESIS). EQUIVALENTLY , ZFFTB COMPUTES
+-C A COMPLEX PERIODIC SEQUENCE FROM ITS FOURIER COEFFICIENTS.
+-C THE TRANSFORM IS DEFINED BELOW AT OUTPUT PARAMETER C.
+-C
+-C A CALL OF ZFFTF FOLLOWED BY A CALL OF ZFFTB WILL MULTIPLY THE
+-C SEQUENCE BY N.
+-C
+-C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE ZFFTB MUST BE
+-C INITIALIZED BY CALLING SUBROUTINE ZFFTI(N,WSAVE).
+-C
+-C INPUT PARAMETERS
+-C
+-C
+-C N      THE LENGTH OF THE COMPLEX SEQUENCE C. THE METHOD IS
+-C        MORE EFFICIENT WHEN N IS THE PRODUCT OF SMALL PRIMES.
+-C
+-C C      A COMPLEX ARRAY OF LENGTH N WHICH CONTAINS THE SEQUENCE
+-C
+-C WSAVE   A REAL WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 4N+15
+-C         IN THE PROGRAM THAT CALLS ZFFTB. THE WSAVE ARRAY MUST BE
+-C         INITIALIZED BY CALLING SUBROUTINE ZFFTI(N,WSAVE) AND A
+-C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
+-C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
+-C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
+-C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
+-C         THE SAME WSAVE ARRAY CAN BE USED BY ZFFTF AND ZFFTB.
+-C
+-C OUTPUT PARAMETERS
+-C
+-C C      FOR J=1,...,N
+-C
+-C            C(J)=THE SUM FROM K=1,...,N OF
+-C
+-C                  C(K)*EXP(I*(J-1)*(K-1)*2*PI/N)
+-C
+-C                        WHERE I=SQRT(-1)
+-C
+-C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT BE
+-C         DESTROYED BETWEEN CALLS OF SUBROUTINE ZFFTF OR ZFFTB
+-C
+-C
+-C
+-C ["SEND INDEX FOR VFFTPK" DESCRIBES A VECTORIZED VERSION OF FFTPACK]
+-C
+-C
+-C
+-
+-      SUBROUTINE ZFFTB1 (N,C,CH,WA,IFAC)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CH(*)      ,C(*)       ,WA(*)      ,IFAC(*)
+-      NF = IFAC(2)
+-      NA = 0
+-      L1 = 1
+-      IW = 1
+-      DO 116 K1=1,NF
+-         IP = IFAC(K1+2)
+-         L2 = IP*L1
+-         IDO = N/L2
+-         IDOT = IDO+IDO
+-         IDL1 = IDOT*L1
+-         IF (IP .NE. 4) GO TO 103
+-         IX2 = IW+IDOT
+-         IX3 = IX2+IDOT
+-         IF (NA .NE. 0) GO TO 101
+-         CALL DPASSB4 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3))
+-         GO TO 102
+-  101    CALL DPASSB4 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3))
+-  102    NA = 1-NA
+-         GO TO 115
+-  103    IF (IP .NE. 2) GO TO 106
+-         IF (NA .NE. 0) GO TO 104
+-         CALL DPASSB2 (IDOT,L1,C,CH,WA(IW))
+-         GO TO 105
+-  104    CALL DPASSB2 (IDOT,L1,CH,C,WA(IW))
+-  105    NA = 1-NA
+-         GO TO 115
+-  106    IF (IP .NE. 3) GO TO 109
+-         IX2 = IW+IDOT
+-         IF (NA .NE. 0) GO TO 107
+-         CALL DPASSB3 (IDOT,L1,C,CH,WA(IW),WA(IX2))
+-         GO TO 108
+-  107    CALL DPASSB3 (IDOT,L1,CH,C,WA(IW),WA(IX2))
+-  108    NA = 1-NA
+-         GO TO 115
+-  109    IF (IP .NE. 5) GO TO 112
+-         IX2 = IW+IDOT
+-         IX3 = IX2+IDOT
+-         IX4 = IX3+IDOT
+-         IF (NA .NE. 0) GO TO 110
+-         CALL DPASSB5 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4))
+-         GO TO 111
+-  110    CALL DPASSB5 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4))
+-  111    NA = 1-NA
+-         GO TO 115
+-  112    IF (NA .NE. 0) GO TO 113
+-         CALL DPASSB (NAC,IDOT,IP,L1,IDL1,C,C,C,CH,CH,WA(IW))
+-         GO TO 114
+-  113    CALL DPASSB (NAC,IDOT,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW))
+-  114    IF (NAC .NE. 0) NA = 1-NA
+-  115    L1 = L2
+-         IW = IW+(IP-1)*IDOT
+-  116 CONTINUE
+-      IF (NA .EQ. 0) RETURN
+-      N2 = N+N
+-      DO 117 I=1,N2
+-         C(I) = CH(I)
+-  117 CONTINUE
+-      RETURN
+-      END
+-
+-      SUBROUTINE ZFFTB (N,C,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       C(*)       ,WSAVE(*)
+-      IF (N .EQ. 1) RETURN
+-      IW1 = N+N+1
+-      IW2 = IW1+N+N
+-      CALL ZFFTB1 (N,C,WSAVE,WSAVE(IW1),WSAVE(IW2))
+-      RETURN
+-      END
+-
+-      SUBROUTINE ZFFTF1 (N,C,CH,WA,IFAC)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CH(*)      ,C(*)       ,WA(*)      ,IFAC(*)
+-      NF = IFAC(2)
+-      NA = 0
+-      L1 = 1
+-      IW = 1
+-      DO 116 K1=1,NF
+-         IP = IFAC(K1+2)
+-         L2 = IP*L1
+-         IDO = N/L2
+-         IDOT = IDO+IDO
+-         IDL1 = IDOT*L1
+-         IF (IP .NE. 4) GO TO 103
+-         IX2 = IW+IDOT
+-         IX3 = IX2+IDOT
+-         IF (NA .NE. 0) GO TO 101
+-         CALL DPASSF4 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3))
+-         GO TO 102
+-  101    CALL DPASSF4 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3))
+-  102    NA = 1-NA
+-         GO TO 115
+-  103    IF (IP .NE. 2) GO TO 106
+-         IF (NA .NE. 0) GO TO 104
+-         CALL DPASSF2 (IDOT,L1,C,CH,WA(IW))
+-         GO TO 105
+-  104    CALL DPASSF2 (IDOT,L1,CH,C,WA(IW))
+-  105    NA = 1-NA
+-         GO TO 115
+-  106    IF (IP .NE. 3) GO TO 109
+-         IX2 = IW+IDOT
+-         IF (NA .NE. 0) GO TO 107
+-         CALL DPASSF3 (IDOT,L1,C,CH,WA(IW),WA(IX2))
+-         GO TO 108
+-  107    CALL DPASSF3 (IDOT,L1,CH,C,WA(IW),WA(IX2))
+-  108    NA = 1-NA
+-         GO TO 115
+-  109    IF (IP .NE. 5) GO TO 112
+-         IX2 = IW+IDOT
+-         IX3 = IX2+IDOT
+-         IX4 = IX3+IDOT
+-         IF (NA .NE. 0) GO TO 110
+-         CALL DPASSF5 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4))
+-         GO TO 111
+-  110    CALL DPASSF5 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4))
+-  111    NA = 1-NA
+-         GO TO 115
+-  112    IF (NA .NE. 0) GO TO 113
+-         CALL DPASSF (NAC,IDOT,IP,L1,IDL1,C,C,C,CH,CH,WA(IW))
+-         GO TO 114
+-  113    CALL DPASSF (NAC,IDOT,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW))
+-  114    IF (NAC .NE. 0) NA = 1-NA
+-  115    L1 = L2
+-         IW = IW+(IP-1)*IDOT
+-  116 CONTINUE
+-      IF (NA .EQ. 0) RETURN
+-      N2 = N+N
+-      DO 117 I=1,N2
+-         C(I) = CH(I)
+-  117 CONTINUE
+-      RETURN
+-      END
+-
+-
+-      SUBROUTINE ZFFTF (N,C,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       C(*)       ,WSAVE(*)
+-      IF (N .EQ. 1) RETURN
+-      IW1 = N+N+1
+-      IW2 = IW1+N+N
+-      CALL ZFFTF1 (N,C,WSAVE,WSAVE(IW1),WSAVE(IW2))
+-      RETURN
+-      END
+-
+-
+-      SUBROUTINE ZFFTI1 (N,WA,IFAC)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       WA(*)      ,IFAC(*)    ,NTRYH(4)
+-      DATA NTRYH(1),NTRYH(2),NTRYH(3),NTRYH(4)/3,4,2,5/
+-      NL = N
+-      NF = 0
+-      J = 0
+-  101 J = J+1
+-      IF (J-4) 102,102,103
+-  102 NTRY = NTRYH(J)
+-      GO TO 104
+-  103 NTRY = NTRY+2
+-  104 NQ = NL/NTRY
+-      NR = NL-NTRY*NQ
+-      IF (NR) 101,105,101
+-  105 NF = NF+1
+-      IFAC(NF+2) = NTRY
+-      NL = NQ
+-      IF (NTRY .NE. 2) GO TO 107
+-      IF (NF .EQ. 1) GO TO 107
+-      DO 106 I=2,NF
+-         IB = NF-I+2
+-         IFAC(IB+2) = IFAC(IB+1)
+-  106 CONTINUE
+-      IFAC(3) = 2
+-  107 IF (NL .NE. 1) GO TO 104
+-      IFAC(1) = N
+-      IFAC(2) = NF
+-      TPI = 6.2831853071795864769252867665590057D0
+-      ARGH = TPI/DBLE(N)
+-      I = 2
+-      L1 = 1
+-      DO 110 K1=1,NF
+-         IP = IFAC(K1+2)
+-         LD = 0
+-         L2 = L1*IP
+-         IDO = N/L2
+-         IDOT = IDO+IDO+2
+-         IPM = IP-1
+-         DO 109 J=1,IPM
+-            I1 = I
+-            WA(I-1) = 1.0D0
+-            WA(I) = 0.0D0
+-            LD = LD+L1
+-            FI = 0.0D0
+-            ARGLD = DBLE(LD)*ARGH
+-            DO 108 II=4,IDOT,2
+-               I = I+2
+-               FI = FI+1.0D0
+-               ARG = FI*ARGLD
+-               WA(I-1) = DCOS(ARG)
+-               WA(I) = DSIN(ARG)
+-  108       CONTINUE
+-            IF (IP .LE. 5) GO TO 109
+-            WA(I1-1) = WA(I-1)
+-            WA(I1) = WA(I)
+-  109    CONTINUE
+-         L1 = L2
+-  110 CONTINUE
+-      RETURN
+-      END
+-
+-      SUBROUTINE ZFFTI (N,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       WSAVE(*)
+-      IF (N .EQ. 1) RETURN
+-      IW1 = N+N+1
+-      IW2 = IW1+N+N
+-      CALL ZFFTI1 (N,WSAVE(IW1),WSAVE(IW2))
+-      RETURN
+-      END
+-
+-      SUBROUTINE DCOSQB1 (N,X,W,XH)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       X(*)       ,W(*)       ,XH(*)
+-      NS2 = (N+1)/2
+-      NP2 = N+2
+-      DO 101 I=3,N,2
+-         XIM1 = X(I-1)+X(I)
+-         X(I) = X(I)-X(I-1)
+-         X(I-1) = XIM1
+-  101 CONTINUE
+-      X(1) = X(1)+X(1)
+-      MODN = MOD(N,2)
+-      IF (MODN .EQ. 0) X(N) = X(N)+X(N)
+-      CALL DFFTB (N,X,XH)
+-      DO 102 K=2,NS2
+-         KC = NP2-K
+-         XH(K) = W(K-1)*X(KC)+W(KC-1)*X(K)
+-         XH(KC) = W(K-1)*X(K)-W(KC-1)*X(KC)
+-  102 CONTINUE
+-      IF (MODN .EQ. 0) X(NS2+1) = W(NS2)*(X(NS2+1)+X(NS2+1))
+-      DO 103 K=2,NS2
+-         KC = NP2-K
+-         X(K) = XH(K)+XH(KC)
+-         X(KC) = XH(K)-XH(KC)
+-  103 CONTINUE
+-      X(1) = X(1)+X(1)
+-      RETURN
+-      END
+-
+-      SUBROUTINE DCOSQF1 (N,X,W,XH)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       X(*)       ,W(*)       ,XH(*)
+-      NS2 = (N+1)/2
+-      NP2 = N+2
+-      DO 101 K=2,NS2
+-         KC = NP2-K
+-         XH(K) = X(K)+X(KC)
+-         XH(KC) = X(K)-X(KC)
+-  101 CONTINUE
+-      MODN = MOD(N,2)
+-      IF (MODN .EQ. 0) XH(NS2+1) = X(NS2+1)+X(NS2+1)
+-      DO 102 K=2,NS2
+-         KC = NP2-K
+-         X(K) = W(K-1)*XH(KC)+W(KC-1)*XH(K)
+-         X(KC) = W(K-1)*XH(K)-W(KC-1)*XH(KC)
+-  102 CONTINUE
+-      IF (MODN .EQ. 0) X(NS2+1) = W(NS2)*XH(NS2+1)
+-      CALL DFFTF (N,X,XH)
+-      DO 103 I=3,N,2
+-         XIM1 = X(I-1)-X(I)
+-         X(I) = X(I-1)+X(I)
+-         X(I-1) = XIM1
+-  103 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DCOSQI (N,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       WSAVE(*)
+-      DATA PIH /1.5707963267948966192313216916397514D0/
+-      DT = PIH/DBLE(N)
+-      FK = 0.0D0
+-      DO 101 K=1,N
+-         FK = FK+1.0D0
+-         WSAVE(K) = DCOS(FK*DT)
+-  101 CONTINUE
+-      CALL DFFTI (N,WSAVE(N+1))
+-      RETURN
+-      END
+-      SUBROUTINE DCOST (N,X,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       X(*)       ,WSAVE(*)
+-      NM1 = N-1
+-      NP1 = N+1
+-      NS2 = N/2
+-      IF (N-2) 106,101,102
+-  101 X1H = X(1)+X(2)
+-      X(2) = X(1)-X(2)
+-      X(1) = X1H
+-      RETURN
+-  102 IF (N .GT. 3) GO TO 103
+-      X1P3 = X(1)+X(3)
+-      TX2 = X(2)+X(2)
+-      X(2) = X(1)-X(3)
+-      X(1) = X1P3+TX2
+-      X(3) = X1P3-TX2
+-      RETURN
+-  103 C1 = X(1)-X(N)
+-      X(1) = X(1)+X(N)
+-      DO 104 K=2,NS2
+-         KC = NP1-K
+-         T1 = X(K)+X(KC)
+-         T2 = X(K)-X(KC)
+-         C1 = C1+WSAVE(KC)*T2
+-         T2 = WSAVE(K)*T2
+-         X(K) = T1-T2
+-         X(KC) = T1+T2
+-  104 CONTINUE
+-      MODN = MOD(N,2)
+-      IF (MODN .NE. 0) X(NS2+1) = X(NS2+1)+X(NS2+1)
+-      CALL DFFTF (NM1,X,WSAVE(N+1))
+-      XIM2 = X(2)
+-      X(2) = C1
+-      DO 105 I=4,N,2
+-         XI = X(I)
+-         X(I) = X(I-2)-X(I-1)
+-         X(I-1) = XIM2
+-         XIM2 = XI
+-  105 CONTINUE
+-      IF (MODN .NE. 0) X(N) = XIM2
+-  106 RETURN
+-      END
+-
+-      SUBROUTINE DZFFT1 (N,WA,IFAC)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       WA(*)      ,IFAC(*)    ,NTRYH(4)
+-      DATA NTRYH(1),NTRYH(2),NTRYH(3),NTRYH(4)/4,2,3,5/
+-     1    ,TPI/6.2831853071795864769252867665590057D0/
+-      NL = N
+-      NF = 0
+-      J = 0
+-  101 J = J+1
+-      IF (J-4) 102,102,103
+-  102 NTRY = NTRYH(J)
+-      GO TO 104
+-  103 NTRY = NTRY+2
+-  104 NQ = NL/NTRY
+-      NR = NL-NTRY*NQ
+-      IF (NR) 101,105,101
+-  105 NF = NF+1
+-      IFAC(NF+2) = NTRY
+-      NL = NQ
+-      IF (NTRY .NE. 2) GO TO 107
+-      IF (NF .EQ. 1) GO TO 107
+-      DO 106 I=2,NF
+-         IB = NF-I+2
+-         IFAC(IB+2) = IFAC(IB+1)
+-  106 CONTINUE
+-      IFAC(3) = 2
+-  107 IF (NL .NE. 1) GO TO 104
+-      IFAC(1) = N
+-      IFAC(2) = NF
+-      ARGH = TPI/DBLE(N)
+-      IS = 0
+-      NFM1 = NF-1
+-      L1 = 1
+-      IF (NFM1 .EQ. 0) RETURN
+-      DO 111 K1=1,NFM1
+-         IP = IFAC(K1+2)
+-         L2 = L1*IP
+-         IDO = N/L2
+-         IPM = IP-1
+-         ARG1 = DBLE(L1)*ARGH
+-         CH1 = 1.0D0
+-         SH1 = 0.0D0
+-         DCH1 = DCOS(ARG1)
+-         DSH1 = DSIN(ARG1)
+-         DO 110 J=1,IPM
+-            CH1H = DCH1*CH1-DSH1*SH1
+-            SH1 = DCH1*SH1+DSH1*CH1
+-            CH1 = CH1H
+-            I = IS+2
+-            WA(I-1) = CH1
+-            WA(I) = SH1
+-            IF (IDO .LT. 5) GO TO 109
+-            DO 108 II=5,IDO,2
+-               I = I+2
+-               WA(I-1) = CH1*WA(I-3)-SH1*WA(I-2)
+-               WA(I) = CH1*WA(I-2)+SH1*WA(I-3)
+-  108       CONTINUE
+-  109       IS = IS+IDO
+-  110    CONTINUE
+-         L1 = L2
+-  111 CONTINUE
+-      RETURN
+-      END
+-
+-      SUBROUTINE DCOSQB (N,X,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       X(*)       ,WSAVE(*)
+-      DATA TSQRT2 /2.8284271247461900976033774484193961D0/
+-      IF (N-2) 101,102,103
+-  101 X(1) = 4.0D0*X(1)
+-      RETURN
+-  102 X1 = 4.0D0*(X(1)+X(2))
+-      X(2) = TSQRT2*(X(1)-X(2))
+-      X(1) = X1
+-      RETURN
+-  103 CALL DCOSQB1 (N,X,WSAVE,WSAVE(N+1))
+-      RETURN
+-      END
+-      SUBROUTINE DCOSQF (N,X,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       X(*)       ,WSAVE(*)
+-      DATA SQRT2 /1.4142135623730950488016887242096980D0/
+-      IF (N-2) 102,101,103
+-  101 TSQX = SQRT2*X(2)
+-      X(2) = X(1)-TSQX
+-      X(1) = X(1)+TSQX
+-  102 RETURN
+-  103 CALL DCOSQF1 (N,X,WSAVE,WSAVE(N+1))
+-      RETURN
+-      END
+-      SUBROUTINE DCOSTI (N,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       WSAVE(*)
+-      DATA PI /3.1415926535897932384626433832795028D0/
+-      IF (N .LE. 3) RETURN
+-      NM1 = N-1
+-      NP1 = N+1
+-      NS2 = N/2
+-      DT = PI/DBLE(NM1)
+-      FK = 0.0D0
+-      DO 101 K=2,NS2
+-         KC = NP1-K
+-         FK = FK+1.0D0
+-         WSAVE(K) = 2.0D0*DSIN(FK*DT)
+-         WSAVE(KC) = 2.0D0*DCOS(FK*DT)
+-  101 CONTINUE
+-      CALL DFFTI (NM1,WSAVE(N+1))
+-      RETURN
+-      END
+-
+-      SUBROUTINE DZFFTB (N,R,AZERO,A,B,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       R(*)       ,A(*)       ,B(*)       ,WSAVE(*)
+-      IF (N-2) 101,102,103
+-  101 R(1) = AZERO
+-      RETURN
+-  102 R(1) = AZERO+A(1)
+-      R(2) = AZERO-A(1)
+-      RETURN
+-  103 NS2 = (N-1)/2
+-      DO 104 I=1,NS2
+-         R(2*I) = .5D0*A(I)
+-         R(2*I+1) = -.5D0*B(I)
+-  104 CONTINUE
+-      R(1) = AZERO
+-      IF (MOD(N,2) .EQ. 0) R(N) = A(NS2+1)
+-      CALL DFFTB (N,R,WSAVE(N+1))
+-      RETURN
+-      END
+-      SUBROUTINE DZFFTF (N,R,AZERO,A,B,WSAVE)
+-C
+-C                       VERSION 3  JUNE 1979
+-C
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       R(*)       ,A(*)       ,B(*)       ,WSAVE(*)
+-      IF (N-2) 101,102,103
+-  101 AZERO = R(1)
+-      RETURN
+-  102 AZERO = .5D0*(R(1)+R(2))
+-      A(1) = .5D0*(R(1)-R(2))
+-      RETURN
+-  103 DO 104 I=1,N
+-         WSAVE(I) = R(I)
+-  104 CONTINUE
+-      CALL DFFTF (N,WSAVE,WSAVE(N+1))
+-      CF = 2.0D0/DBLE(N)
+-      CFM = -CF
+-      AZERO = .5D0*CF*WSAVE(1)
+-      NS2 = (N+1)/2
+-      NS2M = NS2-1
+-      DO 105 I=1,NS2M
+-         A(I) = CF*WSAVE(2*I)
+-         B(I) = CFM*WSAVE(2*I+1)
+-  105 CONTINUE
+-      IF (MOD(N,2) .EQ. 1) RETURN
+-      A(NS2) = .5D0*CF*WSAVE(N)
+-      B(NS2) = 0.0D0
+-      RETURN
+-      END
+-      SUBROUTINE DZFFTI (N,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       WSAVE(*)
+-      IF (N .EQ. 1) RETURN
+-      CALL DZFFT1 (N,WSAVE(2*N+1),WSAVE(3*N+1))
+-      RETURN
+-      END
+-      SUBROUTINE DPASSB (NAC,IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CH(IDO,L1,IP)          ,CC(IDO,IP,L1)          ,
+-     1                C1(IDO,L1,IP)          ,WA(*)      ,C2(IDL1,IP),
+-     2                CH2(IDL1,IP)
+-      IDOT = IDO/2
+-      NT = IP*IDL1
+-      IPP2 = IP+2
+-      IPPH = (IP+1)/2
+-      IDP = IP*IDO
+-C
+-      IF (IDO .LT. L1) GO TO 106
+-      DO 103 J=2,IPPH
+-         JC = IPP2-J
+-         DO 102 K=1,L1
+-            DO 101 I=1,IDO
+-               CH(I,K,J) = CC(I,J,K)+CC(I,JC,K)
+-               CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K)
+-  101       CONTINUE
+-  102    CONTINUE
+-  103 CONTINUE
+-      DO 105 K=1,L1
+-         DO 104 I=1,IDO
+-            CH(I,K,1) = CC(I,1,K)
+-  104    CONTINUE
+-  105 CONTINUE
+-      GO TO 112
+-  106 DO 109 J=2,IPPH
+-         JC = IPP2-J
+-         DO 108 I=1,IDO
+-            DO 107 K=1,L1
+-               CH(I,K,J) = CC(I,J,K)+CC(I,JC,K)
+-               CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K)
+-  107       CONTINUE
+-  108    CONTINUE
+-  109 CONTINUE
+-      DO 111 I=1,IDO
+-         DO 110 K=1,L1
+-            CH(I,K,1) = CC(I,1,K)
+-  110    CONTINUE
+-  111 CONTINUE
+-  112 IDL = 2-IDO
+-      INC = 0
+-      DO 116 L=2,IPPH
+-         LC = IPP2-L
+-         IDL = IDL+IDO
+-         DO 113 IK=1,IDL1
+-            C2(IK,L) = CH2(IK,1)+WA(IDL-1)*CH2(IK,2)
+-            C2(IK,LC) = WA(IDL)*CH2(IK,IP)
+-  113    CONTINUE
+-         IDLJ = IDL
+-         INC = INC+IDO
+-         DO 115 J=3,IPPH
+-            JC = IPP2-J
+-            IDLJ = IDLJ+INC
+-            IF (IDLJ .GT. IDP) IDLJ = IDLJ-IDP
+-            WAR = WA(IDLJ-1)
+-            WAI = WA(IDLJ)
+-            DO 114 IK=1,IDL1
+-               C2(IK,L) = C2(IK,L)+WAR*CH2(IK,J)
+-               C2(IK,LC) = C2(IK,LC)+WAI*CH2(IK,JC)
+-  114       CONTINUE
+-  115    CONTINUE
+-  116 CONTINUE
+-      DO 118 J=2,IPPH
+-         DO 117 IK=1,IDL1
+-            CH2(IK,1) = CH2(IK,1)+CH2(IK,J)
+-  117    CONTINUE
+-  118 CONTINUE
+-      DO 120 J=2,IPPH
+-         JC = IPP2-J
+-         DO 119 IK=2,IDL1,2
+-            CH2(IK-1,J) = C2(IK-1,J)-C2(IK,JC)
+-            CH2(IK-1,JC) = C2(IK-1,J)+C2(IK,JC)
+-            CH2(IK,J) = C2(IK,J)+C2(IK-1,JC)
+-            CH2(IK,JC) = C2(IK,J)-C2(IK-1,JC)
+-  119    CONTINUE
+-  120 CONTINUE
+-      NAC = 1
+-      IF (IDO .EQ. 2) RETURN
+-      NAC = 0
+-      DO 121 IK=1,IDL1
+-         C2(IK,1) = CH2(IK,1)
+-  121 CONTINUE
+-      DO 123 J=2,IP
+-         DO 122 K=1,L1
+-            C1(1,K,J) = CH(1,K,J)
+-            C1(2,K,J) = CH(2,K,J)
+-  122    CONTINUE
+-  123 CONTINUE
+-      IF (IDOT .GT. L1) GO TO 127
+-      IDIJ = 0
+-      DO 126 J=2,IP
+-         IDIJ = IDIJ+2
+-         DO 125 I=4,IDO,2
+-            IDIJ = IDIJ+2
+-            DO 124 K=1,L1
+-               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J)
+-               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J)
+-  124       CONTINUE
+-  125    CONTINUE
+-  126 CONTINUE
+-      RETURN
+-  127 IDJ = 2-IDO
+-      DO 130 J=2,IP
+-         IDJ = IDJ+IDO
+-         DO 129 K=1,L1
+-            IDIJ = IDJ
+-            DO 128 I=4,IDO,2
+-               IDIJ = IDIJ+2
+-               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J)
+-               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J)
+-  128       CONTINUE
+-  129    CONTINUE
+-  130 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DPASSB2 (IDO,L1,CC,CH,WA1)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,2,L1)           ,CH(IDO,L1,2)           ,
+-     1                WA1(*)
+-      IF (IDO .GT. 2) GO TO 102
+-      DO 101 K=1,L1
+-         CH(1,K,1) = CC(1,1,K)+CC(1,2,K)
+-         CH(1,K,2) = CC(1,1,K)-CC(1,2,K)
+-         CH(2,K,1) = CC(2,1,K)+CC(2,2,K)
+-         CH(2,K,2) = CC(2,1,K)-CC(2,2,K)
+-  101 CONTINUE
+-      RETURN
+-  102 DO 104 K=1,L1
+-         DO 103 I=2,IDO,2
+-            CH(I-1,K,1) = CC(I-1,1,K)+CC(I-1,2,K)
+-            TR2 = CC(I-1,1,K)-CC(I-1,2,K)
+-            CH(I,K,1) = CC(I,1,K)+CC(I,2,K)
+-            TI2 = CC(I,1,K)-CC(I,2,K)
+-            CH(I,K,2) = WA1(I-1)*TI2+WA1(I)*TR2
+-            CH(I-1,K,2) = WA1(I-1)*TR2-WA1(I)*TI2
+-  103    CONTINUE
+-  104 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DPASSB3 (IDO,L1,CC,CH,WA1,WA2)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,3,L1)           ,CH(IDO,L1,3)           ,
+-     1                WA1(*)     ,WA2(*)
+-      DATA TAUR,TAUI /-.5D0,.86602540378443864676372317075293618D0/
+-      IF (IDO .NE. 2) GO TO 102
+-      DO 101 K=1,L1
+-         TR2 = CC(1,2,K)+CC(1,3,K)
+-         CR2 = CC(1,1,K)+TAUR*TR2
+-         CH(1,K,1) = CC(1,1,K)+TR2
+-         TI2 = CC(2,2,K)+CC(2,3,K)
+-         CI2 = CC(2,1,K)+TAUR*TI2
+-         CH(2,K,1) = CC(2,1,K)+TI2
+-         CR3 = TAUI*(CC(1,2,K)-CC(1,3,K))
+-         CI3 = TAUI*(CC(2,2,K)-CC(2,3,K))
+-         CH(1,K,2) = CR2-CI3
+-         CH(1,K,3) = CR2+CI3
+-         CH(2,K,2) = CI2+CR3
+-         CH(2,K,3) = CI2-CR3
+-  101 CONTINUE
+-      RETURN
+-  102 DO 104 K=1,L1
+-         DO 103 I=2,IDO,2
+-            TR2 = CC(I-1,2,K)+CC(I-1,3,K)
+-            CR2 = CC(I-1,1,K)+TAUR*TR2
+-            CH(I-1,K,1) = CC(I-1,1,K)+TR2
+-            TI2 = CC(I,2,K)+CC(I,3,K)
+-            CI2 = CC(I,1,K)+TAUR*TI2
+-            CH(I,K,1) = CC(I,1,K)+TI2
+-            CR3 = TAUI*(CC(I-1,2,K)-CC(I-1,3,K))
+-            CI3 = TAUI*(CC(I,2,K)-CC(I,3,K))
+-            DR2 = CR2-CI3
+-            DR3 = CR2+CI3
+-            DI2 = CI2+CR3
+-            DI3 = CI2-CR3
+-            CH(I,K,2) = WA1(I-1)*DI2+WA1(I)*DR2
+-            CH(I-1,K,2) = WA1(I-1)*DR2-WA1(I)*DI2
+-            CH(I,K,3) = WA2(I-1)*DI3+WA2(I)*DR3
+-            CH(I-1,K,3) = WA2(I-1)*DR3-WA2(I)*DI3
+-  103    CONTINUE
+-  104 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DPASSB4 (IDO,L1,CC,CH,WA1,WA2,WA3)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,4,L1)           ,CH(IDO,L1,4)           ,
+-     1                WA1(*)     ,WA2(*)     ,WA3(*)
+-      IF (IDO .NE. 2) GO TO 102
+-      DO 101 K=1,L1
+-         TI1 = CC(2,1,K)-CC(2,3,K)
+-         TI2 = CC(2,1,K)+CC(2,3,K)
+-         TR4 = CC(2,4,K)-CC(2,2,K)
+-         TI3 = CC(2,2,K)+CC(2,4,K)
+-         TR1 = CC(1,1,K)-CC(1,3,K)
+-         TR2 = CC(1,1,K)+CC(1,3,K)
+-         TI4 = CC(1,2,K)-CC(1,4,K)
+-         TR3 = CC(1,2,K)+CC(1,4,K)
+-         CH(1,K,1) = TR2+TR3
+-         CH(1,K,3) = TR2-TR3
+-         CH(2,K,1) = TI2+TI3
+-         CH(2,K,3) = TI2-TI3
+-         CH(1,K,2) = TR1+TR4
+-         CH(1,K,4) = TR1-TR4
+-         CH(2,K,2) = TI1+TI4
+-         CH(2,K,4) = TI1-TI4
+-  101 CONTINUE
+-      RETURN
+-  102 DO 104 K=1,L1
+-         DO 103 I=2,IDO,2
+-            TI1 = CC(I,1,K)-CC(I,3,K)
+-            TI2 = CC(I,1,K)+CC(I,3,K)
+-            TI3 = CC(I,2,K)+CC(I,4,K)
+-            TR4 = CC(I,4,K)-CC(I,2,K)
+-            TR1 = CC(I-1,1,K)-CC(I-1,3,K)
+-            TR2 = CC(I-1,1,K)+CC(I-1,3,K)
+-            TI4 = CC(I-1,2,K)-CC(I-1,4,K)
+-            TR3 = CC(I-1,2,K)+CC(I-1,4,K)
+-            CH(I-1,K,1) = TR2+TR3
+-            CR3 = TR2-TR3
+-            CH(I,K,1) = TI2+TI3
+-            CI3 = TI2-TI3
+-            CR2 = TR1+TR4
+-            CR4 = TR1-TR4
+-            CI2 = TI1+TI4
+-            CI4 = TI1-TI4
+-            CH(I-1,K,2) = WA1(I-1)*CR2-WA1(I)*CI2
+-            CH(I,K,2) = WA1(I-1)*CI2+WA1(I)*CR2
+-            CH(I-1,K,3) = WA2(I-1)*CR3-WA2(I)*CI3
+-            CH(I,K,3) = WA2(I-1)*CI3+WA2(I)*CR3
+-            CH(I-1,K,4) = WA3(I-1)*CR4-WA3(I)*CI4
+-            CH(I,K,4) = WA3(I-1)*CI4+WA3(I)*CR4
+-  103    CONTINUE
+-  104 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DPASSB5 (IDO,L1,CC,CH,WA1,WA2,WA3,WA4)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,5,L1)           ,CH(IDO,L1,5)           ,
+-     1                WA1(*)     ,WA2(*)     ,WA3(*)     ,WA4(*)
+-      DATA TR11,TI11,TR12,TI12 /
+-     1   .30901699437494742410229341718281905D0,
+-     2   .95105651629515357211643933337938214D0,
+-     3  -.80901699437494742410229341718281906D0,
+-     4   .58778525229247312916870595463907276D0/
+-      IF (IDO .NE. 2) GO TO 102
+-      DO 101 K=1,L1
+-         TI5 = CC(2,2,K)-CC(2,5,K)
+-         TI2 = CC(2,2,K)+CC(2,5,K)
+-         TI4 = CC(2,3,K)-CC(2,4,K)
+-         TI3 = CC(2,3,K)+CC(2,4,K)
+-         TR5 = CC(1,2,K)-CC(1,5,K)
+-         TR2 = CC(1,2,K)+CC(1,5,K)
+-         TR4 = CC(1,3,K)-CC(1,4,K)
+-         TR3 = CC(1,3,K)+CC(1,4,K)
+-         CH(1,K,1) = CC(1,1,K)+TR2+TR3
+-         CH(2,K,1) = CC(2,1,K)+TI2+TI3
+-         CR2 = CC(1,1,K)+TR11*TR2+TR12*TR3
+-         CI2 = CC(2,1,K)+TR11*TI2+TR12*TI3
+-         CR3 = CC(1,1,K)+TR12*TR2+TR11*TR3
+-         CI3 = CC(2,1,K)+TR12*TI2+TR11*TI3
+-         CR5 = TI11*TR5+TI12*TR4
+-         CI5 = TI11*TI5+TI12*TI4
+-         CR4 = TI12*TR5-TI11*TR4
+-         CI4 = TI12*TI5-TI11*TI4
+-         CH(1,K,2) = CR2-CI5
+-         CH(1,K,5) = CR2+CI5
+-         CH(2,K,2) = CI2+CR5
+-         CH(2,K,3) = CI3+CR4
+-         CH(1,K,3) = CR3-CI4
+-         CH(1,K,4) = CR3+CI4
+-         CH(2,K,4) = CI3-CR4
+-         CH(2,K,5) = CI2-CR5
+-  101 CONTINUE
+-      RETURN
+-  102 DO 104 K=1,L1
+-         DO 103 I=2,IDO,2
+-            TI5 = CC(I,2,K)-CC(I,5,K)
+-            TI2 = CC(I,2,K)+CC(I,5,K)
+-            TI4 = CC(I,3,K)-CC(I,4,K)
+-            TI3 = CC(I,3,K)+CC(I,4,K)
+-            TR5 = CC(I-1,2,K)-CC(I-1,5,K)
+-            TR2 = CC(I-1,2,K)+CC(I-1,5,K)
+-            TR4 = CC(I-1,3,K)-CC(I-1,4,K)
+-            TR3 = CC(I-1,3,K)+CC(I-1,4,K)
+-            CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3
+-            CH(I,K,1) = CC(I,1,K)+TI2+TI3
+-            CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3
+-            CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3
+-            CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3
+-            CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3
+-            CR5 = TI11*TR5+TI12*TR4
+-            CI5 = TI11*TI5+TI12*TI4
+-            CR4 = TI12*TR5-TI11*TR4
+-            CI4 = TI12*TI5-TI11*TI4
+-            DR3 = CR3-CI4
+-            DR4 = CR3+CI4
+-            DI3 = CI3+CR4
+-            DI4 = CI3-CR4
+-            DR5 = CR2+CI5
+-            DR2 = CR2-CI5
+-            DI5 = CI2-CR5
+-            DI2 = CI2+CR5
+-            CH(I-1,K,2) = WA1(I-1)*DR2-WA1(I)*DI2
+-            CH(I,K,2) = WA1(I-1)*DI2+WA1(I)*DR2
+-            CH(I-1,K,3) = WA2(I-1)*DR3-WA2(I)*DI3
+-            CH(I,K,3) = WA2(I-1)*DI3+WA2(I)*DR3
+-            CH(I-1,K,4) = WA3(I-1)*DR4-WA3(I)*DI4
+-            CH(I,K,4) = WA3(I-1)*DI4+WA3(I)*DR4
+-            CH(I-1,K,5) = WA4(I-1)*DR5-WA4(I)*DI5
+-            CH(I,K,5) = WA4(I-1)*DI5+WA4(I)*DR5
+-  103    CONTINUE
+-  104 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DPASSF (NAC,IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CH(IDO,L1,IP)          ,CC(IDO,IP,L1)          ,
+-     1                C1(IDO,L1,IP)          ,WA(*)      ,C2(IDL1,IP),
+-     2                CH2(IDL1,IP)
+-      IDOT = IDO/2
+-      NT = IP*IDL1
+-      IPP2 = IP+2
+-      IPPH = (IP+1)/2
+-      IDP = IP*IDO
+-C
+-      IF (IDO .LT. L1) GO TO 106
+-      DO 103 J=2,IPPH
+-         JC = IPP2-J
+-         DO 102 K=1,L1
+-            DO 101 I=1,IDO
+-               CH(I,K,J) = CC(I,J,K)+CC(I,JC,K)
+-               CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K)
+-  101       CONTINUE
+-  102    CONTINUE
+-  103 CONTINUE
+-      DO 105 K=1,L1
+-         DO 104 I=1,IDO
+-            CH(I,K,1) = CC(I,1,K)
+-  104    CONTINUE
+-  105 CONTINUE
+-      GO TO 112
+-  106 DO 109 J=2,IPPH
+-         JC = IPP2-J
+-         DO 108 I=1,IDO
+-            DO 107 K=1,L1
+-               CH(I,K,J) = CC(I,J,K)+CC(I,JC,K)
+-               CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K)
+-  107       CONTINUE
+-  108    CONTINUE
+-  109 CONTINUE
+-      DO 111 I=1,IDO
+-         DO 110 K=1,L1
+-            CH(I,K,1) = CC(I,1,K)
+-  110    CONTINUE
+-  111 CONTINUE
+-  112 IDL = 2-IDO
+-      INC = 0
+-      DO 116 L=2,IPPH
+-         LC = IPP2-L
+-         IDL = IDL+IDO
+-         DO 113 IK=1,IDL1
+-            C2(IK,L) = CH2(IK,1)+WA(IDL-1)*CH2(IK,2)
+-            C2(IK,LC) = -WA(IDL)*CH2(IK,IP)
+-  113    CONTINUE
+-         IDLJ = IDL
+-         INC = INC+IDO
+-         DO 115 J=3,IPPH
+-            JC = IPP2-J
+-            IDLJ = IDLJ+INC
+-            IF (IDLJ .GT. IDP) IDLJ = IDLJ-IDP
+-            WAR = WA(IDLJ-1)
+-            WAI = WA(IDLJ)
+-            DO 114 IK=1,IDL1
+-               C2(IK,L) = C2(IK,L)+WAR*CH2(IK,J)
+-               C2(IK,LC) = C2(IK,LC)-WAI*CH2(IK,JC)
+-  114       CONTINUE
+-  115    CONTINUE
+-  116 CONTINUE
+-      DO 118 J=2,IPPH
+-         DO 117 IK=1,IDL1
+-            CH2(IK,1) = CH2(IK,1)+CH2(IK,J)
+-  117    CONTINUE
+-  118 CONTINUE
+-      DO 120 J=2,IPPH
+-         JC = IPP2-J
+-         DO 119 IK=2,IDL1,2
+-            CH2(IK-1,J) = C2(IK-1,J)-C2(IK,JC)
+-            CH2(IK-1,JC) = C2(IK-1,J)+C2(IK,JC)
+-            CH2(IK,J) = C2(IK,J)+C2(IK-1,JC)
+-            CH2(IK,JC) = C2(IK,J)-C2(IK-1,JC)
+-  119    CONTINUE
+-  120 CONTINUE
+-      NAC = 1
+-      IF (IDO .EQ. 2) RETURN
+-      NAC = 0
+-      DO 121 IK=1,IDL1
+-         C2(IK,1) = CH2(IK,1)
+-  121 CONTINUE
+-      DO 123 J=2,IP
+-         DO 122 K=1,L1
+-            C1(1,K,J) = CH(1,K,J)
+-            C1(2,K,J) = CH(2,K,J)
+-  122    CONTINUE
+-  123 CONTINUE
+-      IF (IDOT .GT. L1) GO TO 127
+-      IDIJ = 0
+-      DO 126 J=2,IP
+-         IDIJ = IDIJ+2
+-         DO 125 I=4,IDO,2
+-            IDIJ = IDIJ+2
+-            DO 124 K=1,L1
+-               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)+WA(IDIJ)*CH(I,K,J)
+-               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)-WA(IDIJ)*CH(I-1,K,J)
+-  124       CONTINUE
+-  125    CONTINUE
+-  126 CONTINUE
+-      RETURN
+-  127 IDJ = 2-IDO
+-      DO 130 J=2,IP
+-         IDJ = IDJ+IDO
+-         DO 129 K=1,L1
+-            IDIJ = IDJ
+-            DO 128 I=4,IDO,2
+-               IDIJ = IDIJ+2
+-               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)+WA(IDIJ)*CH(I,K,J)
+-               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)-WA(IDIJ)*CH(I-1,K,J)
+-  128       CONTINUE
+-  129    CONTINUE
+-  130 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DPASSF2 (IDO,L1,CC,CH,WA1)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,2,L1)           ,CH(IDO,L1,2)           ,
+-     1                WA1(*)
+-      IF (IDO .GT. 2) GO TO 102
+-      DO 101 K=1,L1
+-         CH(1,K,1) = CC(1,1,K)+CC(1,2,K)
+-         CH(1,K,2) = CC(1,1,K)-CC(1,2,K)
+-         CH(2,K,1) = CC(2,1,K)+CC(2,2,K)
+-         CH(2,K,2) = CC(2,1,K)-CC(2,2,K)
+-  101 CONTINUE
+-      RETURN
+-  102 DO 104 K=1,L1
+-         DO 103 I=2,IDO,2
+-            CH(I-1,K,1) = CC(I-1,1,K)+CC(I-1,2,K)
+-            TR2 = CC(I-1,1,K)-CC(I-1,2,K)
+-            CH(I,K,1) = CC(I,1,K)+CC(I,2,K)
+-            TI2 = CC(I,1,K)-CC(I,2,K)
+-            CH(I,K,2) = WA1(I-1)*TI2-WA1(I)*TR2
+-            CH(I-1,K,2) = WA1(I-1)*TR2+WA1(I)*TI2
+-  103    CONTINUE
+-  104 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DPASSF3 (IDO,L1,CC,CH,WA1,WA2)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,3,L1)           ,CH(IDO,L1,3)           ,
+-     1                WA1(*)     ,WA2(*)
+-      DATA TAUR,TAUI /-.5D0,-.86602540378443864676372317075293618D0/
+-      IF (IDO .NE. 2) GO TO 102
+-      DO 101 K=1,L1
+-         TR2 = CC(1,2,K)+CC(1,3,K)
+-         CR2 = CC(1,1,K)+TAUR*TR2
+-         CH(1,K,1) = CC(1,1,K)+TR2
+-         TI2 = CC(2,2,K)+CC(2,3,K)
+-         CI2 = CC(2,1,K)+TAUR*TI2
+-         CH(2,K,1) = CC(2,1,K)+TI2
+-         CR3 = TAUI*(CC(1,2,K)-CC(1,3,K))
+-         CI3 = TAUI*(CC(2,2,K)-CC(2,3,K))
+-         CH(1,K,2) = CR2-CI3
+-         CH(1,K,3) = CR2+CI3
+-         CH(2,K,2) = CI2+CR3
+-         CH(2,K,3) = CI2-CR3
+-  101 CONTINUE
+-      RETURN
+-  102 DO 104 K=1,L1
+-         DO 103 I=2,IDO,2
+-            TR2 = CC(I-1,2,K)+CC(I-1,3,K)
+-            CR2 = CC(I-1,1,K)+TAUR*TR2
+-            CH(I-1,K,1) = CC(I-1,1,K)+TR2
+-            TI2 = CC(I,2,K)+CC(I,3,K)
+-            CI2 = CC(I,1,K)+TAUR*TI2
+-            CH(I,K,1) = CC(I,1,K)+TI2
+-            CR3 = TAUI*(CC(I-1,2,K)-CC(I-1,3,K))
+-            CI3 = TAUI*(CC(I,2,K)-CC(I,3,K))
+-            DR2 = CR2-CI3
+-            DR3 = CR2+CI3
+-            DI2 = CI2+CR3
+-            DI3 = CI2-CR3
+-            CH(I,K,2) = WA1(I-1)*DI2-WA1(I)*DR2
+-            CH(I-1,K,2) = WA1(I-1)*DR2+WA1(I)*DI2
+-            CH(I,K,3) = WA2(I-1)*DI3-WA2(I)*DR3
+-            CH(I-1,K,3) = WA2(I-1)*DR3+WA2(I)*DI3
+-  103    CONTINUE
+-  104 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DPASSF4 (IDO,L1,CC,CH,WA1,WA2,WA3)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,4,L1)           ,CH(IDO,L1,4)           ,
+-     1                WA1(*)     ,WA2(*)     ,WA3(*)
+-      IF (IDO .NE. 2) GO TO 102
+-      DO 101 K=1,L1
+-         TI1 = CC(2,1,K)-CC(2,3,K)
+-         TI2 = CC(2,1,K)+CC(2,3,K)
+-         TR4 = CC(2,2,K)-CC(2,4,K)
+-         TI3 = CC(2,2,K)+CC(2,4,K)
+-         TR1 = CC(1,1,K)-CC(1,3,K)
+-         TR2 = CC(1,1,K)+CC(1,3,K)
+-         TI4 = CC(1,4,K)-CC(1,2,K)
+-         TR3 = CC(1,2,K)+CC(1,4,K)
+-         CH(1,K,1) = TR2+TR3
+-         CH(1,K,3) = TR2-TR3
+-         CH(2,K,1) = TI2+TI3
+-         CH(2,K,3) = TI2-TI3
+-         CH(1,K,2) = TR1+TR4
+-         CH(1,K,4) = TR1-TR4
+-         CH(2,K,2) = TI1+TI4
+-         CH(2,K,4) = TI1-TI4
+-  101 CONTINUE
+-      RETURN
+-  102 DO 104 K=1,L1
+-         DO 103 I=2,IDO,2
+-            TI1 = CC(I,1,K)-CC(I,3,K)
+-            TI2 = CC(I,1,K)+CC(I,3,K)
+-            TI3 = CC(I,2,K)+CC(I,4,K)
+-            TR4 = CC(I,2,K)-CC(I,4,K)
+-            TR1 = CC(I-1,1,K)-CC(I-1,3,K)
+-            TR2 = CC(I-1,1,K)+CC(I-1,3,K)
+-            TI4 = CC(I-1,4,K)-CC(I-1,2,K)
+-            TR3 = CC(I-1,2,K)+CC(I-1,4,K)
+-            CH(I-1,K,1) = TR2+TR3
+-            CR3 = TR2-TR3
+-            CH(I,K,1) = TI2+TI3
+-            CI3 = TI2-TI3
+-            CR2 = TR1+TR4
+-            CR4 = TR1-TR4
+-            CI2 = TI1+TI4
+-            CI4 = TI1-TI4
+-            CH(I-1,K,2) = WA1(I-1)*CR2+WA1(I)*CI2
+-            CH(I,K,2) = WA1(I-1)*CI2-WA1(I)*CR2
+-            CH(I-1,K,3) = WA2(I-1)*CR3+WA2(I)*CI3
+-            CH(I,K,3) = WA2(I-1)*CI3-WA2(I)*CR3
+-            CH(I-1,K,4) = WA3(I-1)*CR4+WA3(I)*CI4
+-            CH(I,K,4) = WA3(I-1)*CI4-WA3(I)*CR4
+-  103    CONTINUE
+-  104 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DPASSF5 (IDO,L1,CC,CH,WA1,WA2,WA3,WA4)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,5,L1)           ,CH(IDO,L1,5)           ,
+-     1                WA1(*)     ,WA2(*)     ,WA3(*)     ,WA4(*)
+-      DATA TR11,TI11,TR12,TI12 /
+-     1   .30901699437494742410229341718281905D0,
+-     2  -.95105651629515357211643933337938214D0,
+-     3  -.80901699437494742410229341718281906D0,
+-     4  -.58778525229247312916870595463907276D0/
+-      IF (IDO .NE. 2) GO TO 102
+-      DO 101 K=1,L1
+-         TI5 = CC(2,2,K)-CC(2,5,K)
+-         TI2 = CC(2,2,K)+CC(2,5,K)
+-         TI4 = CC(2,3,K)-CC(2,4,K)
+-         TI3 = CC(2,3,K)+CC(2,4,K)
+-         TR5 = CC(1,2,K)-CC(1,5,K)
+-         TR2 = CC(1,2,K)+CC(1,5,K)
+-         TR4 = CC(1,3,K)-CC(1,4,K)
+-         TR3 = CC(1,3,K)+CC(1,4,K)
+-         CH(1,K,1) = CC(1,1,K)+TR2+TR3
+-         CH(2,K,1) = CC(2,1,K)+TI2+TI3
+-         CR2 = CC(1,1,K)+TR11*TR2+TR12*TR3
+-         CI2 = CC(2,1,K)+TR11*TI2+TR12*TI3
+-         CR3 = CC(1,1,K)+TR12*TR2+TR11*TR3
+-         CI3 = CC(2,1,K)+TR12*TI2+TR11*TI3
+-         CR5 = TI11*TR5+TI12*TR4
+-         CI5 = TI11*TI5+TI12*TI4
+-         CR4 = TI12*TR5-TI11*TR4
+-         CI4 = TI12*TI5-TI11*TI4
+-         CH(1,K,2) = CR2-CI5
+-         CH(1,K,5) = CR2+CI5
+-         CH(2,K,2) = CI2+CR5
+-         CH(2,K,3) = CI3+CR4
+-         CH(1,K,3) = CR3-CI4
+-         CH(1,K,4) = CR3+CI4
+-         CH(2,K,4) = CI3-CR4
+-         CH(2,K,5) = CI2-CR5
+-  101 CONTINUE
+-      RETURN
+-  102 DO 104 K=1,L1
+-         DO 103 I=2,IDO,2
+-            TI5 = CC(I,2,K)-CC(I,5,K)
+-            TI2 = CC(I,2,K)+CC(I,5,K)
+-            TI4 = CC(I,3,K)-CC(I,4,K)
+-            TI3 = CC(I,3,K)+CC(I,4,K)
+-            TR5 = CC(I-1,2,K)-CC(I-1,5,K)
+-            TR2 = CC(I-1,2,K)+CC(I-1,5,K)
+-            TR4 = CC(I-1,3,K)-CC(I-1,4,K)
+-            TR3 = CC(I-1,3,K)+CC(I-1,4,K)
+-            CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3
+-            CH(I,K,1) = CC(I,1,K)+TI2+TI3
+-            CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3
+-            CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3
+-            CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3
+-            CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3
+-            CR5 = TI11*TR5+TI12*TR4
+-            CI5 = TI11*TI5+TI12*TI4
+-            CR4 = TI12*TR5-TI11*TR4
+-            CI4 = TI12*TI5-TI11*TI4
+-            DR3 = CR3-CI4
+-            DR4 = CR3+CI4
+-            DI3 = CI3+CR4
+-            DI4 = CI3-CR4
+-            DR5 = CR2+CI5
+-            DR2 = CR2-CI5
+-            DI5 = CI2-CR5
+-            DI2 = CI2+CR5
+-            CH(I-1,K,2) = WA1(I-1)*DR2+WA1(I)*DI2
+-            CH(I,K,2) = WA1(I-1)*DI2-WA1(I)*DR2
+-            CH(I-1,K,3) = WA2(I-1)*DR3+WA2(I)*DI3
+-            CH(I,K,3) = WA2(I-1)*DI3-WA2(I)*DR3
+-            CH(I-1,K,4) = WA3(I-1)*DR4+WA3(I)*DI4
+-            CH(I,K,4) = WA3(I-1)*DI4-WA3(I)*DR4
+-            CH(I-1,K,5) = WA4(I-1)*DR5+WA4(I)*DI5
+-            CH(I,K,5) = WA4(I-1)*DI5-WA4(I)*DR5
+-  103    CONTINUE
+-  104 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DRADB2 (IDO,L1,CC,CH,WA1)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,2,L1)           ,CH(IDO,L1,2)           ,
+-     1                WA1(*)
+-      DO 101 K=1,L1
+-         CH(1,K,1) = CC(1,1,K)+CC(IDO,2,K)
+-         CH(1,K,2) = CC(1,1,K)-CC(IDO,2,K)
+-  101 CONTINUE
+-      IF (IDO-2) 107,105,102
+-  102 IDP2 = IDO+2
+-      DO 104 K=1,L1
+-         DO 103 I=3,IDO,2
+-            IC = IDP2-I
+-            CH(I-1,K,1) = CC(I-1,1,K)+CC(IC-1,2,K)
+-            TR2 = CC(I-1,1,K)-CC(IC-1,2,K)
+-            CH(I,K,1) = CC(I,1,K)-CC(IC,2,K)
+-            TI2 = CC(I,1,K)+CC(IC,2,K)
+-            CH(I-1,K,2) = WA1(I-2)*TR2-WA1(I-1)*TI2
+-            CH(I,K,2) = WA1(I-2)*TI2+WA1(I-1)*TR2
+-  103    CONTINUE
+-  104 CONTINUE
+-      IF (MOD(IDO,2) .EQ. 1) RETURN
+-  105 DO 106 K=1,L1
+-         CH(IDO,K,1) = CC(IDO,1,K)+CC(IDO,1,K)
+-         CH(IDO,K,2) = -(CC(1,2,K)+CC(1,2,K))
+-  106 CONTINUE
+-  107 RETURN
+-      END
+-      SUBROUTINE DRADB3 (IDO,L1,CC,CH,WA1,WA2)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,3,L1)           ,CH(IDO,L1,3)           ,
+-     1                WA1(*)     ,WA2(*)
+-      DATA TAUR,TAUI /-.5D0,.86602540378443864676372317075293618D0/
+-      DO 101 K=1,L1
+-         TR2 = CC(IDO,2,K)+CC(IDO,2,K)
+-         CR2 = CC(1,1,K)+TAUR*TR2
+-         CH(1,K,1) = CC(1,1,K)+TR2
+-         CI3 = TAUI*(CC(1,3,K)+CC(1,3,K))
+-         CH(1,K,2) = CR2-CI3
+-         CH(1,K,3) = CR2+CI3
+-  101 CONTINUE
+-      IF (IDO .EQ. 1) RETURN
+-      IDP2 = IDO+2
+-      DO 103 K=1,L1
+-         DO 102 I=3,IDO,2
+-            IC = IDP2-I
+-            TR2 = CC(I-1,3,K)+CC(IC-1,2,K)
+-            CR2 = CC(I-1,1,K)+TAUR*TR2
+-            CH(I-1,K,1) = CC(I-1,1,K)+TR2
+-            TI2 = CC(I,3,K)-CC(IC,2,K)
+-            CI2 = CC(I,1,K)+TAUR*TI2
+-            CH(I,K,1) = CC(I,1,K)+TI2
+-            CR3 = TAUI*(CC(I-1,3,K)-CC(IC-1,2,K))
+-            CI3 = TAUI*(CC(I,3,K)+CC(IC,2,K))
+-            DR2 = CR2-CI3
+-            DR3 = CR2+CI3
+-            DI2 = CI2+CR3
+-            DI3 = CI2-CR3
+-            CH(I-1,K,2) = WA1(I-2)*DR2-WA1(I-1)*DI2
+-            CH(I,K,2) = WA1(I-2)*DI2+WA1(I-1)*DR2
+-            CH(I-1,K,3) = WA2(I-2)*DR3-WA2(I-1)*DI3
+-            CH(I,K,3) = WA2(I-2)*DI3+WA2(I-1)*DR3
+-  102    CONTINUE
+-  103 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DRADB4 (IDO,L1,CC,CH,WA1,WA2,WA3)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,4,L1)           ,CH(IDO,L1,4)           ,
+-     1                WA1(*)     ,WA2(*)     ,WA3(*)
+-      DATA SQRT2 /1.4142135623730950488016887242096980D0/
+-      DO 101 K=1,L1
+-         TR1 = CC(1,1,K)-CC(IDO,4,K)
+-         TR2 = CC(1,1,K)+CC(IDO,4,K)
+-         TR3 = CC(IDO,2,K)+CC(IDO,2,K)
+-         TR4 = CC(1,3,K)+CC(1,3,K)
+-         CH(1,K,1) = TR2+TR3
+-         CH(1,K,2) = TR1-TR4
+-         CH(1,K,3) = TR2-TR3
+-         CH(1,K,4) = TR1+TR4
+-  101 CONTINUE
+-      IF (IDO-2) 107,105,102
+-  102 IDP2 = IDO+2
+-      DO 104 K=1,L1
+-         DO 103 I=3,IDO,2
+-            IC = IDP2-I
+-            TI1 = CC(I,1,K)+CC(IC,4,K)
+-            TI2 = CC(I,1,K)-CC(IC,4,K)
+-            TI3 = CC(I,3,K)-CC(IC,2,K)
+-            TR4 = CC(I,3,K)+CC(IC,2,K)
+-            TR1 = CC(I-1,1,K)-CC(IC-1,4,K)
+-            TR2 = CC(I-1,1,K)+CC(IC-1,4,K)
+-            TI4 = CC(I-1,3,K)-CC(IC-1,2,K)
+-            TR3 = CC(I-1,3,K)+CC(IC-1,2,K)
+-            CH(I-1,K,1) = TR2+TR3
+-            CR3 = TR2-TR3
+-            CH(I,K,1) = TI2+TI3
+-            CI3 = TI2-TI3
+-            CR2 = TR1-TR4
+-            CR4 = TR1+TR4
+-            CI2 = TI1+TI4
+-            CI4 = TI1-TI4
+-            CH(I-1,K,2) = WA1(I-2)*CR2-WA1(I-1)*CI2
+-            CH(I,K,2) = WA1(I-2)*CI2+WA1(I-1)*CR2
+-            CH(I-1,K,3) = WA2(I-2)*CR3-WA2(I-1)*CI3
+-            CH(I,K,3) = WA2(I-2)*CI3+WA2(I-1)*CR3
+-            CH(I-1,K,4) = WA3(I-2)*CR4-WA3(I-1)*CI4
+-            CH(I,K,4) = WA3(I-2)*CI4+WA3(I-1)*CR4
+-  103    CONTINUE
+-  104 CONTINUE
+-      IF (MOD(IDO,2) .EQ. 1) RETURN
+-  105 CONTINUE
+-      DO 106 K=1,L1
+-         TI1 = CC(1,2,K)+CC(1,4,K)
+-         TI2 = CC(1,4,K)-CC(1,2,K)
+-         TR1 = CC(IDO,1,K)-CC(IDO,3,K)
+-         TR2 = CC(IDO,1,K)+CC(IDO,3,K)
+-         CH(IDO,K,1) = TR2+TR2
+-         CH(IDO,K,2) = SQRT2*(TR1-TI1)
+-         CH(IDO,K,3) = TI2+TI2
+-         CH(IDO,K,4) = -SQRT2*(TR1+TI1)
+-  106 CONTINUE
+-  107 RETURN
+-      END
+-      SUBROUTINE DRADB5 (IDO,L1,CC,CH,WA1,WA2,WA3,WA4)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,5,L1)           ,CH(IDO,L1,5)           ,
+-     1                WA1(*)     ,WA2(*)     ,WA3(*)     ,WA4(*)
+-      DATA TR11,TI11,TR12,TI12 /
+-     1   .30901699437494742410229341718281905D0,
+-     2   .95105651629515357211643933337938214D0,
+-     3  -.80901699437494742410229341718281906D0,
+-     4   .58778525229247312916870595463907276D0/
+-      DO 101 K=1,L1
+-         TI5 = CC(1,3,K)+CC(1,3,K)
+-         TI4 = CC(1,5,K)+CC(1,5,K)
+-         TR2 = CC(IDO,2,K)+CC(IDO,2,K)
+-         TR3 = CC(IDO,4,K)+CC(IDO,4,K)
+-         CH(1,K,1) = CC(1,1,K)+TR2+TR3
+-         CR2 = CC(1,1,K)+TR11*TR2+TR12*TR3
+-         CR3 = CC(1,1,K)+TR12*TR2+TR11*TR3
+-         CI5 = TI11*TI5+TI12*TI4
+-         CI4 = TI12*TI5-TI11*TI4
+-         CH(1,K,2) = CR2-CI5
+-         CH(1,K,3) = CR3-CI4
+-         CH(1,K,4) = CR3+CI4
+-         CH(1,K,5) = CR2+CI5
+-  101 CONTINUE
+-      IF (IDO .EQ. 1) RETURN
+-      IDP2 = IDO+2
+-      DO 103 K=1,L1
+-         DO 102 I=3,IDO,2
+-            IC = IDP2-I
+-            TI5 = CC(I,3,K)+CC(IC,2,K)
+-            TI2 = CC(I,3,K)-CC(IC,2,K)
+-            TI4 = CC(I,5,K)+CC(IC,4,K)
+-            TI3 = CC(I,5,K)-CC(IC,4,K)
+-            TR5 = CC(I-1,3,K)-CC(IC-1,2,K)
+-            TR2 = CC(I-1,3,K)+CC(IC-1,2,K)
+-            TR4 = CC(I-1,5,K)-CC(IC-1,4,K)
+-            TR3 = CC(I-1,5,K)+CC(IC-1,4,K)
+-            CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3
+-            CH(I,K,1) = CC(I,1,K)+TI2+TI3
+-            CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3
+-            CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3
+-            CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3
+-            CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3
+-            CR5 = TI11*TR5+TI12*TR4
+-            CI5 = TI11*TI5+TI12*TI4
+-            CR4 = TI12*TR5-TI11*TR4
+-            CI4 = TI12*TI5-TI11*TI4
+-            DR3 = CR3-CI4
+-            DR4 = CR3+CI4
+-            DI3 = CI3+CR4
+-            DI4 = CI3-CR4
+-            DR5 = CR2+CI5
+-            DR2 = CR2-CI5
+-            DI5 = CI2-CR5
+-            DI2 = CI2+CR5
+-            CH(I-1,K,2) = WA1(I-2)*DR2-WA1(I-1)*DI2
+-            CH(I,K,2) = WA1(I-2)*DI2+WA1(I-1)*DR2
+-            CH(I-1,K,3) = WA2(I-2)*DR3-WA2(I-1)*DI3
+-            CH(I,K,3) = WA2(I-2)*DI3+WA2(I-1)*DR3
+-            CH(I-1,K,4) = WA3(I-2)*DR4-WA3(I-1)*DI4
+-            CH(I,K,4) = WA3(I-2)*DI4+WA3(I-1)*DR4
+-            CH(I-1,K,5) = WA4(I-2)*DR5-WA4(I-1)*DI5
+-            CH(I,K,5) = WA4(I-2)*DI5+WA4(I-1)*DR5
+-  102    CONTINUE
+-  103 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DRADBG (IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CH(IDO,L1,IP)          ,CC(IDO,IP,L1)          ,
+-     1                C1(IDO,L1,IP)          ,C2(IDL1,IP),
+-     2                CH2(IDL1,IP)           ,WA(*)
+-      DATA TPI/6.2831853071795864769252867665590057D0/
+-      ARG = TPI/DBLE(IP)
+-      DCP = DCOS(ARG)
+-      DSP = DSIN(ARG)
+-      IDP2 = IDO+2
+-      NBD = (IDO-1)/2
+-      IPP2 = IP+2
+-      IPPH = (IP+1)/2
+-      IF (IDO .LT. L1) GO TO 103
+-      DO 102 K=1,L1
+-         DO 101 I=1,IDO
+-            CH(I,K,1) = CC(I,1,K)
+-  101    CONTINUE
+-  102 CONTINUE
+-      GO TO 106
+-  103 DO 105 I=1,IDO
+-         DO 104 K=1,L1
+-            CH(I,K,1) = CC(I,1,K)
+-  104    CONTINUE
+-  105 CONTINUE
+-  106 DO 108 J=2,IPPH
+-         JC = IPP2-J
+-         J2 = J+J
+-         DO 107 K=1,L1
+-            CH(1,K,J) = CC(IDO,J2-2,K)+CC(IDO,J2-2,K)
+-            CH(1,K,JC) = CC(1,J2-1,K)+CC(1,J2-1,K)
+-  107    CONTINUE
+-  108 CONTINUE
+-      IF (IDO .EQ. 1) GO TO 116
+-      IF (NBD .LT. L1) GO TO 112
+-      DO 111 J=2,IPPH
+-         JC = IPP2-J
+-         DO 110 K=1,L1
+-            DO 109 I=3,IDO,2
+-               IC = IDP2-I
+-               CH(I-1,K,J) = CC(I-1,2*J-1,K)+CC(IC-1,2*J-2,K)
+-               CH(I-1,K,JC) = CC(I-1,2*J-1,K)-CC(IC-1,2*J-2,K)
+-               CH(I,K,J) = CC(I,2*J-1,K)-CC(IC,2*J-2,K)
+-               CH(I,K,JC) = CC(I,2*J-1,K)+CC(IC,2*J-2,K)
+-  109       CONTINUE
+-  110    CONTINUE
+-  111 CONTINUE
+-      GO TO 116
+-  112 DO 115 J=2,IPPH
+-         JC = IPP2-J
+-         DO 114 I=3,IDO,2
+-            IC = IDP2-I
+-            DO 113 K=1,L1
+-               CH(I-1,K,J) = CC(I-1,2*J-1,K)+CC(IC-1,2*J-2,K)
+-               CH(I-1,K,JC) = CC(I-1,2*J-1,K)-CC(IC-1,2*J-2,K)
+-               CH(I,K,J) = CC(I,2*J-1,K)-CC(IC,2*J-2,K)
+-               CH(I,K,JC) = CC(I,2*J-1,K)+CC(IC,2*J-2,K)
+-  113       CONTINUE
+-  114    CONTINUE
+-  115 CONTINUE
+-  116 AR1 = 1.0D0
+-      AI1 = 0.0D0
+-      DO 120 L=2,IPPH
+-         LC = IPP2-L
+-         AR1H = DCP*AR1-DSP*AI1
+-         AI1 = DCP*AI1+DSP*AR1
+-         AR1 = AR1H
+-         DO 117 IK=1,IDL1
+-            C2(IK,L) = CH2(IK,1)+AR1*CH2(IK,2)
+-            C2(IK,LC) = AI1*CH2(IK,IP)
+-  117    CONTINUE
+-         DC2 = AR1
+-         DS2 = AI1
+-         AR2 = AR1
+-         AI2 = AI1
+-         DO 119 J=3,IPPH
+-            JC = IPP2-J
+-            AR2H = DC2*AR2-DS2*AI2
+-            AI2 = DC2*AI2+DS2*AR2
+-            AR2 = AR2H
+-            DO 118 IK=1,IDL1
+-               C2(IK,L) = C2(IK,L)+AR2*CH2(IK,J)
+-               C2(IK,LC) = C2(IK,LC)+AI2*CH2(IK,JC)
+-  118       CONTINUE
+-  119    CONTINUE
+-  120 CONTINUE
+-      DO 122 J=2,IPPH
+-         DO 121 IK=1,IDL1
+-            CH2(IK,1) = CH2(IK,1)+CH2(IK,J)
+-  121    CONTINUE
+-  122 CONTINUE
+-      DO 124 J=2,IPPH
+-         JC = IPP2-J
+-         DO 123 K=1,L1
+-            CH(1,K,J) = C1(1,K,J)-C1(1,K,JC)
+-            CH(1,K,JC) = C1(1,K,J)+C1(1,K,JC)
+-  123    CONTINUE
+-  124 CONTINUE
+-      IF (IDO .EQ. 1) GO TO 132
+-      IF (NBD .LT. L1) GO TO 128
+-      DO 127 J=2,IPPH
+-         JC = IPP2-J
+-         DO 126 K=1,L1
+-            DO 125 I=3,IDO,2
+-               CH(I-1,K,J) = C1(I-1,K,J)-C1(I,K,JC)
+-               CH(I-1,K,JC) = C1(I-1,K,J)+C1(I,K,JC)
+-               CH(I,K,J) = C1(I,K,J)+C1(I-1,K,JC)
+-               CH(I,K,JC) = C1(I,K,J)-C1(I-1,K,JC)
+-  125       CONTINUE
+-  126    CONTINUE
+-  127 CONTINUE
+-      GO TO 132
+-  128 DO 131 J=2,IPPH
+-         JC = IPP2-J
+-         DO 130 I=3,IDO,2
+-            DO 129 K=1,L1
+-               CH(I-1,K,J) = C1(I-1,K,J)-C1(I,K,JC)
+-               CH(I-1,K,JC) = C1(I-1,K,J)+C1(I,K,JC)
+-               CH(I,K,J) = C1(I,K,J)+C1(I-1,K,JC)
+-               CH(I,K,JC) = C1(I,K,J)-C1(I-1,K,JC)
+-  129       CONTINUE
+-  130    CONTINUE
+-  131 CONTINUE
+-  132 CONTINUE
+-      IF (IDO .EQ. 1) RETURN
+-      DO 133 IK=1,IDL1
+-         C2(IK,1) = CH2(IK,1)
+-  133 CONTINUE
+-      DO 135 J=2,IP
+-         DO 134 K=1,L1
+-            C1(1,K,J) = CH(1,K,J)
+-  134    CONTINUE
+-  135 CONTINUE
+-      IF (NBD .GT. L1) GO TO 139
+-      IS = -IDO
+-      DO 138 J=2,IP
+-         IS = IS+IDO
+-         IDIJ = IS
+-         DO 137 I=3,IDO,2
+-            IDIJ = IDIJ+2
+-            DO 136 K=1,L1
+-               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J)
+-               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J)
+-  136       CONTINUE
+-  137    CONTINUE
+-  138 CONTINUE
+-      GO TO 143
+-  139 IS = -IDO
+-      DO 142 J=2,IP
+-         IS = IS+IDO
+-         DO 141 K=1,L1
+-            IDIJ = IS
+-            DO 140 I=3,IDO,2
+-               IDIJ = IDIJ+2
+-               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J)
+-               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J)
+-  140       CONTINUE
+-  141    CONTINUE
+-  142 CONTINUE
+-  143 RETURN
+-      END
+-      SUBROUTINE DRADF2 (IDO,L1,CC,CH,WA1)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CH(IDO,2,L1)           ,CC(IDO,L1,2)           ,
+-     1                WA1(*)
+-      DO 101 K=1,L1
+-         CH(1,1,K) = CC(1,K,1)+CC(1,K,2)
+-         CH(IDO,2,K) = CC(1,K,1)-CC(1,K,2)
+-  101 CONTINUE
+-      IF (IDO-2) 107,105,102
+-  102 IDP2 = IDO+2
+-      DO 104 K=1,L1
+-         DO 103 I=3,IDO,2
+-            IC = IDP2-I
+-            TR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2)
+-            TI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2)
+-            CH(I,1,K) = CC(I,K,1)+TI2
+-            CH(IC,2,K) = TI2-CC(I,K,1)
+-            CH(I-1,1,K) = CC(I-1,K,1)+TR2
+-            CH(IC-1,2,K) = CC(I-1,K,1)-TR2
+-  103    CONTINUE
+-  104 CONTINUE
+-      IF (MOD(IDO,2) .EQ. 1) RETURN
+-  105 DO 106 K=1,L1
+-         CH(1,2,K) = -CC(IDO,K,2)
+-         CH(IDO,1,K) = CC(IDO,K,1)
+-  106 CONTINUE
+-  107 RETURN
+-      END
+-      SUBROUTINE DRADF3 (IDO,L1,CC,CH,WA1,WA2)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CH(IDO,3,L1)           ,CC(IDO,L1,3)           ,
+-     1                WA1(*)     ,WA2(*)
+-      DATA TAUR,TAUI /-.5D0,.86602540378443864676372317075293618D0/
+-      DO 101 K=1,L1
+-         CR2 = CC(1,K,2)+CC(1,K,3)
+-         CH(1,1,K) = CC(1,K,1)+CR2
+-         CH(1,3,K) = TAUI*(CC(1,K,3)-CC(1,K,2))
+-         CH(IDO,2,K) = CC(1,K,1)+TAUR*CR2
+-  101 CONTINUE
+-      IF (IDO .EQ. 1) RETURN
+-      IDP2 = IDO+2
+-      DO 103 K=1,L1
+-         DO 102 I=3,IDO,2
+-            IC = IDP2-I
+-            DR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2)
+-            DI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2)
+-            DR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3)
+-            DI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3)
+-            CR2 = DR2+DR3
+-            CI2 = DI2+DI3
+-            CH(I-1,1,K) = CC(I-1,K,1)+CR2
+-            CH(I,1,K) = CC(I,K,1)+CI2
+-            TR2 = CC(I-1,K,1)+TAUR*CR2
+-            TI2 = CC(I,K,1)+TAUR*CI2
+-            TR3 = TAUI*(DI2-DI3)
+-            TI3 = TAUI*(DR3-DR2)
+-            CH(I-1,3,K) = TR2+TR3
+-            CH(IC-1,2,K) = TR2-TR3
+-            CH(I,3,K) = TI2+TI3
+-            CH(IC,2,K) = TI3-TI2
+-  102    CONTINUE
+-  103 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DRADF4 (IDO,L1,CC,CH,WA1,WA2,WA3)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,L1,4)           ,CH(IDO,4,L1)           ,
+-     1                WA1(*)     ,WA2(*)     ,WA3(*)
+-      DATA HSQT2 /0.70710678118654752440084436210484904D0/
+-      DO 101 K=1,L1
+-         TR1 = CC(1,K,2)+CC(1,K,4)
+-         TR2 = CC(1,K,1)+CC(1,K,3)
+-         CH(1,1,K) = TR1+TR2
+-         CH(IDO,4,K) = TR2-TR1
+-         CH(IDO,2,K) = CC(1,K,1)-CC(1,K,3)
+-         CH(1,3,K) = CC(1,K,4)-CC(1,K,2)
+-  101 CONTINUE
+-      IF (IDO-2) 107,105,102
+-  102 IDP2 = IDO+2
+-      DO 104 K=1,L1
+-         DO 103 I=3,IDO,2
+-            IC = IDP2-I
+-            CR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2)
+-            CI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2)
+-            CR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3)
+-            CI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3)
+-            CR4 = WA3(I-2)*CC(I-1,K,4)+WA3(I-1)*CC(I,K,4)
+-            CI4 = WA3(I-2)*CC(I,K,4)-WA3(I-1)*CC(I-1,K,4)
+-            TR1 = CR2+CR4
+-            TR4 = CR4-CR2
+-            TI1 = CI2+CI4
+-            TI4 = CI2-CI4
+-            TI2 = CC(I,K,1)+CI3
+-            TI3 = CC(I,K,1)-CI3
+-            TR2 = CC(I-1,K,1)+CR3
+-            TR3 = CC(I-1,K,1)-CR3
+-            CH(I-1,1,K) = TR1+TR2
+-            CH(IC-1,4,K) = TR2-TR1
+-            CH(I,1,K) = TI1+TI2
+-            CH(IC,4,K) = TI1-TI2
+-            CH(I-1,3,K) = TI4+TR3
+-            CH(IC-1,2,K) = TR3-TI4
+-            CH(I,3,K) = TR4+TI3
+-            CH(IC,2,K) = TR4-TI3
+-  103    CONTINUE
+-  104 CONTINUE
+-      IF (MOD(IDO,2) .EQ. 1) RETURN
+-  105 CONTINUE
+-      DO 106 K=1,L1
+-         TI1 = -HSQT2*(CC(IDO,K,2)+CC(IDO,K,4))
+-         TR1 = HSQT2*(CC(IDO,K,2)-CC(IDO,K,4))
+-         CH(IDO,1,K) = TR1+CC(IDO,K,1)
+-         CH(IDO,3,K) = CC(IDO,K,1)-TR1
+-         CH(1,2,K) = TI1-CC(IDO,K,3)
+-         CH(1,4,K) = TI1+CC(IDO,K,3)
+-  106 CONTINUE
+-  107 RETURN
+-      END
+-      SUBROUTINE DRADF5 (IDO,L1,CC,CH,WA1,WA2,WA3,WA4)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CC(IDO,L1,5)           ,CH(IDO,5,L1)           ,
+-     1                WA1(*)     ,WA2(*)     ,WA3(*)     ,WA4(*)
+-      DATA TR11,TI11,TR12,TI12 /
+-     1   .30901699437494742410229341718281905D0,
+-     2   .95105651629515357211643933337938214D0,
+-     3  -.80901699437494742410229341718281906D0,
+-     4   .58778525229247312916870595463907276D0/
+-      DO 101 K=1,L1
+-         CR2 = CC(1,K,5)+CC(1,K,2)
+-         CI5 = CC(1,K,5)-CC(1,K,2)
+-         CR3 = CC(1,K,4)+CC(1,K,3)
+-         CI4 = CC(1,K,4)-CC(1,K,3)
+-         CH(1,1,K) = CC(1,K,1)+CR2+CR3
+-         CH(IDO,2,K) = CC(1,K,1)+TR11*CR2+TR12*CR3
+-         CH(1,3,K) = TI11*CI5+TI12*CI4
+-         CH(IDO,4,K) = CC(1,K,1)+TR12*CR2+TR11*CR3
+-         CH(1,5,K) = TI12*CI5-TI11*CI4
+-  101 CONTINUE
+-      IF (IDO .EQ. 1) RETURN
+-      IDP2 = IDO+2
+-      DO 103 K=1,L1
+-         DO 102 I=3,IDO,2
+-            IC = IDP2-I
+-            DR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2)
+-            DI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2)
+-            DR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3)
+-            DI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3)
+-            DR4 = WA3(I-2)*CC(I-1,K,4)+WA3(I-1)*CC(I,K,4)
+-            DI4 = WA3(I-2)*CC(I,K,4)-WA3(I-1)*CC(I-1,K,4)
+-            DR5 = WA4(I-2)*CC(I-1,K,5)+WA4(I-1)*CC(I,K,5)
+-            DI5 = WA4(I-2)*CC(I,K,5)-WA4(I-1)*CC(I-1,K,5)
+-            CR2 = DR2+DR5
+-            CI5 = DR5-DR2
+-            CR5 = DI2-DI5
+-            CI2 = DI2+DI5
+-            CR3 = DR3+DR4
+-            CI4 = DR4-DR3
+-            CR4 = DI3-DI4
+-            CI3 = DI3+DI4
+-            CH(I-1,1,K) = CC(I-1,K,1)+CR2+CR3
+-            CH(I,1,K) = CC(I,K,1)+CI2+CI3
+-            TR2 = CC(I-1,K,1)+TR11*CR2+TR12*CR3
+-            TI2 = CC(I,K,1)+TR11*CI2+TR12*CI3
+-            TR3 = CC(I-1,K,1)+TR12*CR2+TR11*CR3
+-            TI3 = CC(I,K,1)+TR12*CI2+TR11*CI3
+-            TR5 = TI11*CR5+TI12*CR4
+-            TI5 = TI11*CI5+TI12*CI4
+-            TR4 = TI12*CR5-TI11*CR4
+-            TI4 = TI12*CI5-TI11*CI4
+-            CH(I-1,3,K) = TR2+TR5
+-            CH(IC-1,2,K) = TR2-TR5
+-            CH(I,3,K) = TI2+TI5
+-            CH(IC,2,K) = TI5-TI2
+-            CH(I-1,5,K) = TR3+TR4
+-            CH(IC-1,4,K) = TR3-TR4
+-            CH(I,5,K) = TI3+TI4
+-            CH(IC,4,K) = TI4-TI3
+-  102    CONTINUE
+-  103 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DRADFG (IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CH(IDO,L1,IP)          ,CC(IDO,IP,L1)          ,
+-     1                C1(IDO,L1,IP)          ,C2(IDL1,IP),
+-     2                CH2(IDL1,IP)           ,WA(*)
+-      DATA TPI/6.2831853071795864769252867665590057D0/
+-      ARG = TPI/DBLE(IP)
+-      DCP = DCOS(ARG)
+-      DSP = DSIN(ARG)
+-      IPPH = (IP+1)/2
+-      IPP2 = IP+2
+-      IDP2 = IDO+2
+-      NBD = (IDO-1)/2
+-      IF (IDO .EQ. 1) GO TO 119
+-      DO 101 IK=1,IDL1
+-         CH2(IK,1) = C2(IK,1)
+-  101 CONTINUE
+-      DO 103 J=2,IP
+-         DO 102 K=1,L1
+-            CH(1,K,J) = C1(1,K,J)
+-  102    CONTINUE
+-  103 CONTINUE
+-      IF (NBD .GT. L1) GO TO 107
+-      IS = -IDO
+-      DO 106 J=2,IP
+-         IS = IS+IDO
+-         IDIJ = IS
+-         DO 105 I=3,IDO,2
+-            IDIJ = IDIJ+2
+-            DO 104 K=1,L1
+-               CH(I-1,K,J) = WA(IDIJ-1)*C1(I-1,K,J)+WA(IDIJ)*C1(I,K,J)
+-               CH(I,K,J) = WA(IDIJ-1)*C1(I,K,J)-WA(IDIJ)*C1(I-1,K,J)
+-  104       CONTINUE
+-  105    CONTINUE
+-  106 CONTINUE
+-      GO TO 111
+-  107 IS = -IDO
+-      DO 110 J=2,IP
+-         IS = IS+IDO
+-         DO 109 K=1,L1
+-            IDIJ = IS
+-            DO 108 I=3,IDO,2
+-               IDIJ = IDIJ+2
+-               CH(I-1,K,J) = WA(IDIJ-1)*C1(I-1,K,J)+WA(IDIJ)*C1(I,K,J)
+-               CH(I,K,J) = WA(IDIJ-1)*C1(I,K,J)-WA(IDIJ)*C1(I-1,K,J)
+-  108       CONTINUE
+-  109    CONTINUE
+-  110 CONTINUE
+-  111 IF (NBD .LT. L1) GO TO 115
+-      DO 114 J=2,IPPH
+-         JC = IPP2-J
+-         DO 113 K=1,L1
+-            DO 112 I=3,IDO,2
+-               C1(I-1,K,J) = CH(I-1,K,J)+CH(I-1,K,JC)
+-               C1(I-1,K,JC) = CH(I,K,J)-CH(I,K,JC)
+-               C1(I,K,J) = CH(I,K,J)+CH(I,K,JC)
+-               C1(I,K,JC) = CH(I-1,K,JC)-CH(I-1,K,J)
+-  112       CONTINUE
+-  113    CONTINUE
+-  114 CONTINUE
+-      GO TO 121
+-  115 DO 118 J=2,IPPH
+-         JC = IPP2-J
+-         DO 117 I=3,IDO,2
+-            DO 116 K=1,L1
+-               C1(I-1,K,J) = CH(I-1,K,J)+CH(I-1,K,JC)
+-               C1(I-1,K,JC) = CH(I,K,J)-CH(I,K,JC)
+-               C1(I,K,J) = CH(I,K,J)+CH(I,K,JC)
+-               C1(I,K,JC) = CH(I-1,K,JC)-CH(I-1,K,J)
+-  116       CONTINUE
+-  117    CONTINUE
+-  118 CONTINUE
+-      GO TO 121
+-  119 DO 120 IK=1,IDL1
+-         C2(IK,1) = CH2(IK,1)
+-  120 CONTINUE
+-  121 DO 123 J=2,IPPH
+-         JC = IPP2-J
+-         DO 122 K=1,L1
+-            C1(1,K,J) = CH(1,K,J)+CH(1,K,JC)
+-            C1(1,K,JC) = CH(1,K,JC)-CH(1,K,J)
+-  122    CONTINUE
+-  123 CONTINUE
+-C
+-      AR1 = 1.0D0
+-      AI1 = 0.0D0
+-      DO 127 L=2,IPPH
+-         LC = IPP2-L
+-         AR1H = DCP*AR1-DSP*AI1
+-         AI1 = DCP*AI1+DSP*AR1
+-         AR1 = AR1H
+-         DO 124 IK=1,IDL1
+-            CH2(IK,L) = C2(IK,1)+AR1*C2(IK,2)
+-            CH2(IK,LC) = AI1*C2(IK,IP)
+-  124    CONTINUE
+-         DC2 = AR1
+-         DS2 = AI1
+-         AR2 = AR1
+-         AI2 = AI1
+-         DO 126 J=3,IPPH
+-            JC = IPP2-J
+-            AR2H = DC2*AR2-DS2*AI2
+-            AI2 = DC2*AI2+DS2*AR2
+-            AR2 = AR2H
+-            DO 125 IK=1,IDL1
+-               CH2(IK,L) = CH2(IK,L)+AR2*C2(IK,J)
+-               CH2(IK,LC) = CH2(IK,LC)+AI2*C2(IK,JC)
+-  125       CONTINUE
+-  126    CONTINUE
+-  127 CONTINUE
+-      DO 129 J=2,IPPH
+-         DO 128 IK=1,IDL1
+-            CH2(IK,1) = CH2(IK,1)+C2(IK,J)
+-  128    CONTINUE
+-  129 CONTINUE
+-C
+-      IF (IDO .LT. L1) GO TO 132
+-      DO 131 K=1,L1
+-         DO 130 I=1,IDO
+-            CC(I,1,K) = CH(I,K,1)
+-  130    CONTINUE
+-  131 CONTINUE
+-      GO TO 135
+-  132 DO 134 I=1,IDO
+-         DO 133 K=1,L1
+-            CC(I,1,K) = CH(I,K,1)
+-  133    CONTINUE
+-  134 CONTINUE
+-  135 DO 137 J=2,IPPH
+-         JC = IPP2-J
+-         J2 = J+J
+-         DO 136 K=1,L1
+-            CC(IDO,J2-2,K) = CH(1,K,J)
+-            CC(1,J2-1,K) = CH(1,K,JC)
+-  136    CONTINUE
+-  137 CONTINUE
+-      IF (IDO .EQ. 1) RETURN
+-      IF (NBD .LT. L1) GO TO 141
+-      DO 140 J=2,IPPH
+-         JC = IPP2-J
+-         J2 = J+J
+-         DO 139 K=1,L1
+-            DO 138 I=3,IDO,2
+-               IC = IDP2-I
+-               CC(I-1,J2-1,K) = CH(I-1,K,J)+CH(I-1,K,JC)
+-               CC(IC-1,J2-2,K) = CH(I-1,K,J)-CH(I-1,K,JC)
+-               CC(I,J2-1,K) = CH(I,K,J)+CH(I,K,JC)
+-               CC(IC,J2-2,K) = CH(I,K,JC)-CH(I,K,J)
+-  138       CONTINUE
+-  139    CONTINUE
+-  140 CONTINUE
+-      RETURN
+-  141 DO 144 J=2,IPPH
+-         JC = IPP2-J
+-         J2 = J+J
+-         DO 143 I=3,IDO,2
+-            IC = IDP2-I
+-            DO 142 K=1,L1
+-               CC(I-1,J2-1,K) = CH(I-1,K,J)+CH(I-1,K,JC)
+-               CC(IC-1,J2-2,K) = CH(I-1,K,J)-CH(I-1,K,JC)
+-               CC(I,J2-1,K) = CH(I,K,J)+CH(I,K,JC)
+-               CC(IC,J2-2,K) = CH(I,K,JC)-CH(I,K,J)
+-  142       CONTINUE
+-  143    CONTINUE
+-  144 CONTINUE
+-      RETURN
+-      END
+-
+-      SUBROUTINE DFFTB1 (N,C,CH,WA,IFAC)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CH(*)      ,C(*)       ,WA(*)      ,IFAC(*)
+-      NF = IFAC(2)
+-      NA = 0
+-      L1 = 1
+-      IW = 1
+-      DO 116 K1=1,NF
+-         IP = IFAC(K1+2)
+-         L2 = IP*L1
+-         IDO = N/L2
+-         IDL1 = IDO*L1
+-         IF (IP .NE. 4) GO TO 103
+-         IX2 = IW+IDO
+-         IX3 = IX2+IDO
+-         IF (NA .NE. 0) GO TO 101
+-         CALL DRADB4 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3))
+-         GO TO 102
+-  101    CALL DRADB4 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3))
+-  102    NA = 1-NA
+-         GO TO 115
+-  103    IF (IP .NE. 2) GO TO 106
+-         IF (NA .NE. 0) GO TO 104
+-         CALL DRADB2 (IDO,L1,C,CH,WA(IW))
+-         GO TO 105
+-  104    CALL DRADB2 (IDO,L1,CH,C,WA(IW))
+-  105    NA = 1-NA
+-         GO TO 115
+-  106    IF (IP .NE. 3) GO TO 109
+-         IX2 = IW+IDO
+-         IF (NA .NE. 0) GO TO 107
+-         CALL DRADB3 (IDO,L1,C,CH,WA(IW),WA(IX2))
+-         GO TO 108
+-  107    CALL DRADB3 (IDO,L1,CH,C,WA(IW),WA(IX2))
+-  108    NA = 1-NA
+-         GO TO 115
+-  109    IF (IP .NE. 5) GO TO 112
+-         IX2 = IW+IDO
+-         IX3 = IX2+IDO
+-         IX4 = IX3+IDO
+-         IF (NA .NE. 0) GO TO 110
+-         CALL DRADB5 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4))
+-         GO TO 111
+-  110    CALL DRADB5 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4))
+-  111    NA = 1-NA
+-         GO TO 115
+-  112    IF (NA .NE. 0) GO TO 113
+-         CALL DRADBG (IDO,IP,L1,IDL1,C,C,C,CH,CH,WA(IW))
+-         GO TO 114
+-  113    CALL DRADBG (IDO,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW))
+-  114    IF (IDO .EQ. 1) NA = 1-NA
+-  115    L1 = L2
+-         IW = IW+(IP-1)*IDO
+-  116 CONTINUE
+-      IF (NA .EQ. 0) RETURN
+-      DO 117 I=1,N
+-         C(I) = CH(I)
+-  117 CONTINUE
+-      RETURN
+-      END
+-
+-
+-      SUBROUTINE DFFTB (N,R,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       R(*)       ,WSAVE(*)
+-      IF (N .EQ. 1) RETURN
+-      CALL DFFTB1 (N,R,WSAVE,WSAVE(N+1),WSAVE(2*N+1))
+-      RETURN
+-      END
+-
+-      SUBROUTINE DFFTF1 (N,C,CH,WA,IFAC)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       CH(*)      ,C(*)       ,WA(*)      ,IFAC(*)
+-      NF = IFAC(2)
+-      NA = 1
+-      L2 = N
+-      IW = N
+-      DO 111 K1=1,NF
+-         KH = NF-K1
+-         IP = IFAC(KH+3)
+-         L1 = L2/IP
+-         IDO = N/L2
+-         IDL1 = IDO*L1
+-         IW = IW-(IP-1)*IDO
+-         NA = 1-NA
+-         IF (IP .NE. 4) GO TO 102
+-         IX2 = IW+IDO
+-         IX3 = IX2+IDO
+-         IF (NA .NE. 0) GO TO 101
+-         CALL DRADF4 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3))
+-         GO TO 110
+-  101    CALL DRADF4 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3))
+-         GO TO 110
+-  102    IF (IP .NE. 2) GO TO 104
+-         IF (NA .NE. 0) GO TO 103
+-         CALL DRADF2 (IDO,L1,C,CH,WA(IW))
+-         GO TO 110
+-  103    CALL DRADF2 (IDO,L1,CH,C,WA(IW))
+-         GO TO 110
+-  104    IF (IP .NE. 3) GO TO 106
+-         IX2 = IW+IDO
+-         IF (NA .NE. 0) GO TO 105
+-         CALL DRADF3 (IDO,L1,C,CH,WA(IW),WA(IX2))
+-         GO TO 110
+-  105    CALL DRADF3 (IDO,L1,CH,C,WA(IW),WA(IX2))
+-         GO TO 110
+-  106    IF (IP .NE. 5) GO TO 108
+-         IX2 = IW+IDO
+-         IX3 = IX2+IDO
+-         IX4 = IX3+IDO
+-         IF (NA .NE. 0) GO TO 107
+-         CALL DRADF5 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4))
+-         GO TO 110
+-  107    CALL DRADF5 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4))
+-         GO TO 110
+-  108    IF (IDO .EQ. 1) NA = 1-NA
+-         IF (NA .NE. 0) GO TO 109
+-         CALL DRADFG (IDO,IP,L1,IDL1,C,C,C,CH,CH,WA(IW))
+-         NA = 1
+-         GO TO 110
+-  109    CALL DRADFG (IDO,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW))
+-         NA = 0
+-  110    L2 = L1
+-  111 CONTINUE
+-      IF (NA .EQ. 1) RETURN
+-      DO 112 I=1,N
+-         C(I) = CH(I)
+-  112 CONTINUE
+-      RETURN
+-      END
+-
+-
+-      SUBROUTINE DFFTF (N,R,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       R(*)       ,WSAVE(*)
+-      IF (N .EQ. 1) RETURN
+-      CALL DFFTF1 (N,R,WSAVE,WSAVE(N+1),WSAVE(2*N+1))
+-      RETURN
+-      END
+-
+-      SUBROUTINE DFFTI1 (N,WA,IFAC)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       WA(*)      ,IFAC(*)    ,NTRYH(4)
+-      DATA NTRYH(1),NTRYH(2),NTRYH(3),NTRYH(4)/4,2,3,5/
+-      NL = N
+-      NF = 0
+-      J = 0
+-  101 J = J+1
+-      IF (J-4) 102,102,103
+-  102 NTRY = NTRYH(J)
+-      GO TO 104
+-  103 NTRY = NTRY+2
+-  104 NQ = NL/NTRY
+-      NR = NL-NTRY*NQ
+-      IF (NR) 101,105,101
+-  105 NF = NF+1
+-      IFAC(NF+2) = NTRY
+-      NL = NQ
+-      IF (NTRY .NE. 2) GO TO 107
+-      IF (NF .EQ. 1) GO TO 107
+-      DO 106 I=2,NF
+-         IB = NF-I+2
+-         IFAC(IB+2) = IFAC(IB+1)
+-  106 CONTINUE
+-      IFAC(3) = 2
+-  107 IF (NL .NE. 1) GO TO 104
+-      IFAC(1) = N
+-      IFAC(2) = NF
+-      TPI = 6.2831853071795864769252867665590057D0
+-      ARGH = TPI/DBLE(N)
+-      IS = 0
+-      NFM1 = NF-1
+-      L1 = 1
+-      IF (NFM1 .EQ. 0) RETURN
+-      DO 110 K1=1,NFM1
+-         IP = IFAC(K1+2)
+-         LD = 0
+-         L2 = L1*IP
+-         IDO = N/L2
+-         IPM = IP-1
+-         DO 109 J=1,IPM
+-            LD = LD+L1
+-            I = IS
+-            ARGLD = DBLE(LD)*ARGH
+-            FI = 0.0D0
+-            DO 108 II=3,IDO,2
+-               I = I+2
+-               FI = FI+1.0D0
+-               ARG = FI*ARGLD
+-               WA(I-1) = DCOS(ARG)
+-               WA(I) = DSIN(ARG)
+-  108       CONTINUE
+-            IS = IS+IDO
+-  109    CONTINUE
+-         L1 = L2
+-  110 CONTINUE
+-      RETURN
+-      END
+-
+-      SUBROUTINE DFFTI (N,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       WSAVE(*)
+-      IF (N .EQ. 1) RETURN
+-      CALL DFFTI1 (N,WSAVE(N+1),WSAVE(2*N+1))
+-      RETURN
+-      END
+-      SUBROUTINE DSINQB (N,X,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       X(*)       ,WSAVE(*)
+-      IF (N .GT. 1) GO TO 101
+-      X(1) = 4.0D0*X(1)
+-      RETURN
+-  101 NS2 = N/2
+-      DO 102 K=2,N,2
+-         X(K) = -X(K)
+-  102 CONTINUE
+-      CALL DCOSQB (N,X,WSAVE)
+-      DO 103 K=1,NS2
+-         KC = N-K
+-         XHOLD = X(K)
+-         X(K) = X(KC+1)
+-         X(KC+1) = XHOLD
+-  103 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DSINQF (N,X,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       X(*)       ,WSAVE(*)
+-      IF (N .EQ. 1) RETURN
+-      NS2 = N/2
+-      DO 101 K=1,NS2
+-         KC = N-K
+-         XHOLD = X(K)
+-         X(K) = X(KC+1)
+-         X(KC+1) = XHOLD
+-  101 CONTINUE
+-      CALL DCOSQF (N,X,WSAVE)
+-      DO 102 K=2,N,2
+-         X(K) = -X(K)
+-  102 CONTINUE
+-      RETURN
+-      END
+-      SUBROUTINE DSINQI (N,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       WSAVE(*)
+-      CALL DCOSQI (N,WSAVE)
+-      RETURN
+-      END
+-
+-      SUBROUTINE DSINT1(N,WAR,WAS,XH,X,IFAC)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION WAR(*),WAS(*),X(*),XH(*),IFAC(*)
+-      DATA SQRT3 /1.7320508075688772935274463415058723D0/
+-      DO 100 I=1,N
+-      XH(I) = WAR(I)
+-      WAR(I) = X(I)
+-  100 CONTINUE
+-      IF (N-2) 101,102,103
+-  101 XH(1) = XH(1)+XH(1)
+-      GO TO 106
+-  102 XHOLD = SQRT3*(XH(1)+XH(2))
+-      XH(2) = SQRT3*(XH(1)-XH(2))
+-      XH(1) = XHOLD
+-      GO TO 106
+-  103 NP1 = N+1
+-      NS2 = N/2
+-      X(1) = 0.0D0
+-      DO 104 K=1,NS2
+-         KC = NP1-K
+-         T1 = XH(K)-XH(KC)
+-         T2 = WAS(K)*(XH(K)+XH(KC))
+-         X(K+1) = T1+T2
+-         X(KC+1) = T2-T1
+-  104 CONTINUE
+-      MODN = MOD(N,2)
+-      IF (MODN .NE. 0) X(NS2+2) = 4.0D0*XH(NS2+1)
+-      CALL DFFTF1 (NP1,X,XH,WAR,IFAC)
+-      XH(1) = .5D0*X(1)
+-      DO 105 I=3,N,2
+-         XH(I-1) = -X(I)
+-         XH(I) = XH(I-2)+X(I-1)
+-  105 CONTINUE
+-      IF (MODN .NE. 0) GO TO 106
+-      XH(N) = -X(N+1)
+-  106 DO 107 I=1,N
+-      X(I) = WAR(I)
+-      WAR(I) = XH(I)
+-  107 CONTINUE
+-      RETURN
+-      END
+-
+-      SUBROUTINE DSINT (N,X,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       X(*)       ,WSAVE(*)
+-      NP1 = N+1
+-      IW1 = N/2+1
+-      IW2 = IW1+NP1
+-      IW3 = IW2+NP1
+-      CALL DSINT1(N,X,WSAVE,WSAVE(IW1),WSAVE(IW2),WSAVE(IW3))
+-      RETURN
+-      END
+-
+-      SUBROUTINE DSINTI (N,WSAVE)
+-	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
+-      DIMENSION       WSAVE(*)
+-      DATA PI /3.1415926535897932384626433832795028D0/
+-      IF (N .LE. 1) RETURN
+-      NS2 = N/2
+-      NP1 = N+1
+-      DT = PI/DBLE(NP1)
+-      DO 101 K=1,NS2
+-         WSAVE(K) = 2.0D0*DSIN(K*DT)
+-  101 CONTINUE
+-      CALL DFFTI (NP1,WSAVE(NS2+1))
+-      RETURN
+-      END
+diff --git a/scipy/linalg/src/id_dist/src/id_rand.f b/scipy/linalg/src/id_dist/src/id_rand.f
+deleted file mode 100644
+index b49d2ef1f..000000000
+--- a/scipy/linalg/src/id_dist/src/id_rand.f
++++ /dev/null
+@@ -1,379 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine id_frand generates pseudorandom numbers
+-c       drawn uniformly from [0,1]. id_frand is more
+-c       efficient that id_srand, but cannot generate
+-c       fewer than 55 pseudorandom numbers per call.
+-c
+-c       routine id_srand generates pseudorandom numbers
+-c       drawn uniformly from [0,1]. id_srand is less
+-c       efficient that id_frand, but can generate
+-c       fewer than 55 pseudorandom numbers per call.
+-c
+-c       entry id_frandi initializes the seed values
+-c       for routine id_frand.
+-c
+-c       entry id_srandi initializes the seed values
+-c       for routine id_srand.
+-c
+-c       entry id_frando initializes the seed values
+-c       for routine id_frand to their original values.
+-c
+-c       entry id_srando initializes the seed values
+-c       for routine id_srand to their original values.
+-c
+-c       routine id_randperm generates a uniformly random permutation.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine id_frand(n,r)
+-c
+-c       generates n pseudorandom numbers drawn uniformly from [0,1],
+-c       via a very efficient lagged Fibonnaci method.
+-c       Unlike routine id_srand, the present routine requires that
+-c       n be at least 55.
+-c
+-c       input:
+-c       n -- number of pseudorandom numbers to generate
+-c
+-c       output:
+-c       r -- array of pseudorandom numbers
+-c
+-c       _N.B._: n must be at least 55.
+-c
+-c       reference:
+-c       Press, Teukolsky, Vetterling, Flannery, "Numerical Recipes,"
+-c            3rd edition, Cambridge University Press, 2007,
+-c            Section 7.1.5.
+-c
+-        implicit none
+-        integer n,k
+-        real*8 r(n),s(55),t(55),s0(55),x
+-        save
+-c
+-        data s/
+-     1  0.2793574644042651d0, 0.1882566493961346d0,
+-     2  0.5202478134503912d0, 0.7568505373052146d0,
+-     3  0.5682465992936152d0, 0.5153148754383294d0,
+-     4  0.7806554095454596d0, 1.982474428974643d-2,
+-     5  0.2520464262278498d0, 0.6423784715775962d0,
+-     6  0.5802024387972178d0, 0.3784471040388249d0,
+-     7  7.839919528229308d-2, 0.6334519212594525d0,
+-     8  3.387627157788001d-2, 0.1709066283884670d0,
+-     9  0.4801610983518325d0, 0.8983424668099422d0,
+-     *  5.358948687598758d-2, 0.1265377231771848d0,
+-     1  0.8979988627693677d0, 0.6470084038238917d0,
+-     2  0.3031709395541237d0, 0.6674702804438126d0,
+-     3  0.6318240977112699d0, 0.2235229633873050d0,
+-     4  0.2784629939177633d0, 0.2365462014457445d0,
+-     5  0.7226213454977284d0, 0.8986523045307989d0,
+-     6  0.5488233229247885d0, 0.3924605412141200d0,
+-     7  0.6288356378374988d0, 0.6370664115760445d0,
+-     8  0.5925600062791174d0, 0.4322113919396362d0,
+-     9  0.9766098520360393d0, 0.5168619893947437d0,
+-     *  0.6799970440779681d0, 0.4196004604766881d0,
+-     1  0.2324473089903044d0, 0.1439046416143282d0,
+-     2  0.4670307948601256d0, 0.7076498261128343d0,
+-     3  0.9458030397562582d0, 0.4557892460080424d0,
+-     4  0.3905930854589403d0, 0.3361770064397268d0,
+-     5  0.8303274937900278d0, 0.3041110304032945d0,
+-     6  0.5752684022049654d0, 7.985703137991175d-2,
+-     7  0.5522643936454465d0, 1.956754937251801d-2,
+-     8  0.9920272858340107d0/
+-c
+-        data s0/
+-     1  0.2793574644042651d0, 0.1882566493961346d0,
+-     2  0.5202478134503912d0, 0.7568505373052146d0,
+-     3  0.5682465992936152d0, 0.5153148754383294d0,
+-     4  0.7806554095454596d0, 1.982474428974643d-2,
+-     5  0.2520464262278498d0, 0.6423784715775962d0,
+-     6  0.5802024387972178d0, 0.3784471040388249d0,
+-     7  7.839919528229308d-2, 0.6334519212594525d0,
+-     8  3.387627157788001d-2, 0.1709066283884670d0,
+-     9  0.4801610983518325d0, 0.8983424668099422d0,
+-     *  5.358948687598758d-2, 0.1265377231771848d0,
+-     1  0.8979988627693677d0, 0.6470084038238917d0,
+-     2  0.3031709395541237d0, 0.6674702804438126d0,
+-     3  0.6318240977112699d0, 0.2235229633873050d0,
+-     4  0.2784629939177633d0, 0.2365462014457445d0,
+-     5  0.7226213454977284d0, 0.8986523045307989d0,
+-     6  0.5488233229247885d0, 0.3924605412141200d0,
+-     7  0.6288356378374988d0, 0.6370664115760445d0,
+-     8  0.5925600062791174d0, 0.4322113919396362d0,
+-     9  0.9766098520360393d0, 0.5168619893947437d0,
+-     *  0.6799970440779681d0, 0.4196004604766881d0,
+-     1  0.2324473089903044d0, 0.1439046416143282d0,
+-     2  0.4670307948601256d0, 0.7076498261128343d0,
+-     3  0.9458030397562582d0, 0.4557892460080424d0,
+-     4  0.3905930854589403d0, 0.3361770064397268d0,
+-     5  0.8303274937900278d0, 0.3041110304032945d0,
+-     6  0.5752684022049654d0, 7.985703137991175d-2,
+-     7  0.5522643936454465d0, 1.956754937251801d-2,
+-     8  0.9920272858340107d0/
+-c
+-c
+-        do k = 1,24
+-c
+-          x = s(k+31)-s(k)
+-          if(x .lt. 0) x = x+1
+-          r(k) = x
+-c
+-        enddo ! k
+-c
+-c
+-        do k = 25,55
+-c
+-          x = r(k-24)-s(k)
+-          if(x .lt. 0) x = x+1
+-          r(k) = x
+-c
+-        enddo ! k
+-c
+-c
+-        do k = 56,n
+-c
+-          x = r(k-24)-r(k-55)
+-          if(x .lt. 0) x = x+1
+-          r(k) = x
+-c
+-        enddo ! k
+-c
+-c
+-        do k = 1,55
+-          s(k) = r(n-55+k)
+-        enddo ! k
+-c
+-c
+-        return
+-c
+-c
+-c
+-        entry id_frandi(t)
+-c
+-c       initializes the seed values in s
+-c       (any appropriately random numbers will do).
+-c
+-c       input:
+-c       t -- values to copy into s
+-c
+-        do k = 1,55
+-          s(k) = t(k)
+-        enddo ! k
+-c
+-        return
+-c
+-c
+-c
+-        entry id_frando()
+-c
+-c       initializes the seed values in s to their original values.
+-c
+-        do k = 1,55
+-          s(k) = s0(k)
+-        enddo ! k
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine id_srand(n,r)
+-c
+-c       generates n pseudorandom numbers drawn uniformly from [0,1],
+-c       via a very efficient lagged Fibonnaci method.
+-c       Unlike routine id_frand, the present routine does not requires
+-c       that n be at least 55.
+-c
+-c       input:
+-c       n -- number of pseudorandom numbers to generate
+-c
+-c       output:
+-c       r -- array of pseudorandom numbers
+-c
+-c       reference:
+-c       Press, Teukolsky, Vetterling, Flannery, "Numerical Recipes,"
+-c            3rd edition, Cambridge University Press, 2007,
+-c            Section 7.1.5.
+-c
+-        implicit none
+-        integer n,k,l,m
+-        real*8 s(55),r(n),s0(55),t(55),x
+-        save
+-c
+-        data l/55/,m/24/
+-c
+-        data s/
+-     1  0.8966049453474352d0, 0.7789471911260157d0,
+-     2  0.6071529762908476d0, 0.8287077988663865d0,
+-     3  0.8249336255502409d0, 0.5735259423199479d0,
+-     4  0.2436346323812991d0, 0.2656149927259701d0,
+-     5  0.6594784809929011d0, 0.3432392503145575d0,
+-     6  0.5051287353012308d0, 0.1444493249757482d0,
+-     7  0.7643753221285416d0, 0.4843422506977382d0,
+-     8  0.4427513254774826d0, 0.2965991475108561d0,
+-     9  0.2650513544474467d0, 2.768759325778929d-2,
+-     *  0.6106305243078063d0, 0.4246918885003141d0,
+-     1  0.2863757386932874d0, 0.6211983878375777d0,
+-     2  0.7534336463880467d0, 0.7471458603576737d0,
+-     3  0.2017455446928328d0, 0.9334235874832779d0,
+-     4  0.6343440435422822d0, 0.8819824804812527d0,
+-     5  1.994761401222460d-2, 0.7023693520374801d0,
+-     6  0.6010088924817263d0, 6.498095955562046d-2,
+-     7  0.3090915456102685d0, 0.3014924769096677d0,
+-     8  0.5820726822705102d0, 0.3630527222866207d0,
+-     9  0.3787166916242271d0, 0.3932772088505305d0,
+-     *  0.5570720335382000d0, 0.9712062146993835d0,
+-     1  0.1338293907964648d0, 0.1857441593107195d0,
+-     2  0.9102503893692572d0, 0.2623337538798778d0,
+-     3  0.3542828591321135d0, 2.246286032456513d-2,
+-     4  0.7935703170405717d0, 6.051464729640567d-2,
+-     5  0.7271929955172147d0, 1.968513010678739d-3,
+-     6  0.4914223624495486d0, 0.8730023176789450d0,
+-     7  0.9639777091743168d0, 0.1084256187532446d0,
+-     8  0.8539399636754000d0/
+-c
+-        data s0/
+-     1  0.8966049453474352d0, 0.7789471911260157d0,
+-     2  0.6071529762908476d0, 0.8287077988663865d0,
+-     3  0.8249336255502409d0, 0.5735259423199479d0,
+-     4  0.2436346323812991d0, 0.2656149927259701d0,
+-     5  0.6594784809929011d0, 0.3432392503145575d0,
+-     6  0.5051287353012308d0, 0.1444493249757482d0,
+-     7  0.7643753221285416d0, 0.4843422506977382d0,
+-     8  0.4427513254774826d0, 0.2965991475108561d0,
+-     9  0.2650513544474467d0, 2.768759325778929d-2,
+-     *  0.6106305243078063d0, 0.4246918885003141d0,
+-     1  0.2863757386932874d0, 0.6211983878375777d0,
+-     2  0.7534336463880467d0, 0.7471458603576737d0,
+-     3  0.2017455446928328d0, 0.9334235874832779d0,
+-     4  0.6343440435422822d0, 0.8819824804812527d0,
+-     5  1.994761401222460d-2, 0.7023693520374801d0,
+-     6  0.6010088924817263d0, 6.498095955562046d-2,
+-     7  0.3090915456102685d0, 0.3014924769096677d0,
+-     8  0.5820726822705102d0, 0.3630527222866207d0,
+-     9  0.3787166916242271d0, 0.3932772088505305d0,
+-     *  0.5570720335382000d0, 0.9712062146993835d0,
+-     1  0.1338293907964648d0, 0.1857441593107195d0,
+-     2  0.9102503893692572d0, 0.2623337538798778d0,
+-     3  0.3542828591321135d0, 2.246286032456513d-2,
+-     4  0.7935703170405717d0, 6.051464729640567d-2,
+-     5  0.7271929955172147d0, 1.968513010678739d-3,
+-     6  0.4914223624495486d0, 0.8730023176789450d0,
+-     7  0.9639777091743168d0, 0.1084256187532446d0,
+-     8  0.8539399636754000d0/
+-c
+-c
+-        do k = 1,n
+-c
+-c         Run one step of the recurrence.
+-c
+-          x = s(m)-s(l)
+-          if(x .lt. 0) x = x+1
+-          s(l) = x
+-          r(k) = x
+-c
+-c         Decrement l and m.
+-c
+-          l = l-1
+-          m = m-1
+-c
+-c         Circle back to the end if required.
+-c
+-          if(l .eq. 0) l = 55
+-          if(m .eq. 0) m = 55
+-c
+-        enddo ! k
+-c
+-c
+-        return
+-c
+-c
+-c
+-        entry id_srandi(t)
+-c
+-c       initializes the seed values in s
+-c       (any appropriately random numbers will do).
+-c
+-c       input:
+-c       t -- values to copy into s
+-c
+-        do k = 1,55
+-          s(k) = t(k)
+-        enddo ! k
+-c
+-        l = 55
+-        m = 24
+-c
+-        return
+-c
+-c
+-c
+-        entry id_srando()
+-c
+-c       initializes the seed values in s to their original values.
+-c
+-        do k = 1,55
+-          s(k) = s0(k)
+-        enddo ! k
+-c
+-        l = 55
+-        m = 24
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine id_randperm(n,ind)
+-c
+-c       draws a permutation ind uniformly at random from the group
+-c       of all permutations of n objects.
+-c
+-c       input:
+-c       n -- length of ind
+-c
+-c       output:
+-c       ind -- random permutation of length n
+-c
+-        implicit none
+-        integer n,ind(n),m,j,iswap
+-        real*8 r
+-c
+-c
+-c       Initialize ind.
+-c
+-        do j = 1,n
+-          ind(j) = j
+-        enddo ! j
+-c
+-c
+-c       Shuffle ind via the Fisher-Yates (Knuth/Durstenfeld) algorithm.
+-c
+-        do m = n,2,-1
+-c
+-c         Draw an integer uniformly at random from 1, 2, ..., m.
+-c
+-          call id_srand(1,r)
+-          j = m*r+1
+-c
+-c         Uncomment the following line if r could equal 1:
+-c         if(j .eq. m+1) j = m
+-c
+-c         Swap ind(j) and ind(m).
+-c
+-          iswap = ind(j)
+-          ind(j) = ind(m)
+-          ind(m) = iswap
+-c
+-        enddo ! m
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/id_rtrans.f b/scipy/linalg/src/id_dist/src/id_rtrans.f
+deleted file mode 100644
+index a970d7fb5..000000000
+--- a/scipy/linalg/src/id_dist/src/id_rtrans.f
++++ /dev/null
+@@ -1,746 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idd_random_transf applies rapidly
+-c       a random orthogonal matrix to a user-supplied vector.
+-c
+-c       routine idd_random_transf_inverse applies rapidly
+-c       the inverse of the operator applied
+-c       by routine idd_random_transf.
+-c
+-c       routine idz_random_transf applies rapidly
+-c       a random unitary matrix to a user-supplied vector.
+-c
+-c       routine idz_random_transf_inverse applies rapidly
+-c       the inverse of the operator applied
+-c       by routine idz_random_transf.
+-c
+-c       routine idd_random_transf_init initializes data
+-c       for routines idd_random_transf and idd_random_transf_inverse.
+-c
+-c       routine idz_random_transf_init initializes data
+-c       for routines idz_random_transf and idz_random_transf_inverse.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-c
+-        subroutine idd_random_transf_init(nsteps,n,w,keep)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension w(*)
+-c
+-c       prepares and stores in array w the data used
+-c       by the routines idd_random_transf and idd_random_transf_inverse
+-c       to apply rapidly a random orthogonal matrix
+-c       to an arbitrary user-specified vector.
+-c
+-c       input:
+-c       nsteps -- the degree of randomness of the operator
+-c                 to be applied
+-c       n -- the size of the matrix to be applied
+-c
+-c       output:
+-c       w -- the first keep elements of w contain all the data
+-c            to be used by routines idd_random_tranf
+-c            and idd_random_transf_inverse. Please note that
+-c            the number of elements used by the present routine
+-c            is also equal to keep. This array should be at least
+-c            3*nsteps*n + 2*n + n/4 + 50 real*8 elements long.
+-c       keep - the number of elements in w actually used
+-c              by the present routine; keep is also the number
+-c              of elements that must not be changed between the call
+-c              to this routine and subsequent calls to routines
+-c              idd_random_transf and idd_random_transf_inverse.
+-c
+-c
+-c        . . . allocate memory
+-c
+-        ninire=2
+-c
+-        ialbetas=10
+-        lalbetas=2*n*nsteps+10
+-c
+-        iixs=ialbetas+lalbetas
+-        lixs=n*nsteps/ninire+10
+-c
+-        iww=iixs+lixs
+-        lww=2*n+n/4+20
+-c
+-        keep=iww+lww
+-c
+-        w(1)=ialbetas+0.1
+-        w(2)=iixs+0.1
+-        w(3)=nsteps+0.1
+-        w(4)=iww+0.1
+-        w(5)=n+0.1
+-c
+-        call idd_random_transf_init0(nsteps,n,w(ialbetas),w(iixs))
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idz_random_transf_init(nsteps,n,w,keep)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension w(*)
+-c
+-c       prepares and stores in array w the data used
+-c       by routines idz_random_transf and idz_random_transf_inverse
+-c       to apply rapidly a random unitary matrix
+-c       to an arbitrary user-specified vector.
+-c
+-c       input:
+-c       nsteps -- the degree of randomness of the operator
+-c                 to be applied
+-c       n -- the size of the matrix to be applied
+-c
+-c       output:
+-c       w -- the first keep elements of w contain all the data
+-c            to be used by routines idz_random_transf
+-c            and idz_random_transf_inverse. Please note that
+-c            the number of elements used by the present routine
+-c            is also equal to keep. This array should be at least
+-c            5*nsteps*n + 2*n + n/4 + 60 real*8 elements long.
+-c       keep - the number of elements in w actually used
+-c              by the present routine; keep is also the number
+-c              of elements that must not be changed between the call
+-c              to this routine and subsequent calls to routines
+-c              idz_random_transf and idz_random_transf_inverse.
+-c
+-c
+-c        . . . allocate memory
+-c
+-        ninire=2
+-c
+-        ialbetas=10
+-        lalbetas=2*n*nsteps+10
+-c
+-        igammas=ialbetas+lalbetas
+-        lgammas=2*n*nsteps+10
+-c
+-        iixs=igammas+lgammas
+-        lixs=n*nsteps/ninire+10
+-c
+-        iww=iixs+lixs
+-        lww=2*n+n/4+20
+-c
+-        keep=iww+lww
+-c
+-        w(1)=ialbetas+0.1
+-        w(2)=iixs+0.1
+-        w(3)=nsteps+0.1
+-        w(4)=iww+0.1
+-        w(5)=n+0.1
+-        w(6)=igammas+0.1
+-c
+-        call idz_random_transf_init0(nsteps,n,w(ialbetas),
+-     1      w(igammas),w(iixs))
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idd_random_transf(x,y,w)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension x(*),y(*),w(*)
+-c
+-c       applies rapidly a random orthogonal matrix
+-c       to the user-specified real vector x,
+-c       using the data in array w stored there by a preceding
+-c       call to routine idd_random_transf_init.
+-c
+-c       input:
+-c       x -- the vector of length n to which the random matrix is
+-c            to be applied
+-c       w -- array containing all initialization data
+-c
+-c       output:
+-c       y -- the result of applying the random matrix to x
+-c
+-c
+-c        . . . allocate memory
+-c
+-        ialbetas=w(1)
+-        iixs=w(2)
+-        nsteps=w(3)
+-        iww=w(4)
+-        n=w(5)
+-c
+-        call idd_random_transf0(nsteps,x,y,n,w(iww),
+-     1      w(ialbetas),w(iixs))
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idd_random_transf_inverse(x,y,w)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension x(*),y(*),w(*)
+-c
+-c       applies rapidly a random orthogonal matrix
+-c       to the user-specified real vector x,
+-c       using the data in array w stored there by a preceding
+-c       call to routine idd_random_transf_init.
+-c       The transformation applied by the present routine is
+-c       the inverse of the transformation applied
+-c       by routine idd_random_transf.
+-c
+-c       input:
+-c       x -- the vector of length n to which the random matrix is
+-c            to be applied
+-c       w -- array containing all initialization data
+-c
+-c       output:
+-c       y -- the result of applying the random matrix to x
+-c
+-c
+-c        . . . allocate memory
+-c
+-        ialbetas=w(1)
+-        iixs=w(2)
+-        nsteps=w(3)
+-        iww=w(4)
+-        n=w(5)
+-c
+-        call idd_random_transf0_inv(nsteps,x,y,n,w(iww),
+-     1      w(ialbetas),w(iixs))
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idz_random_transf(x,y,w)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        complex *16 x(*),y(*)
+-        dimension w(*)
+-c
+-c       applies rapidly a random unitary matrix
+-c       to the user-specified vector x,
+-c       using the data in array w stored there by a preceding
+-c       call to routine idz_random_transf_init.
+-c
+-c       input:
+-c       x -- the vector of length n to which the random matrix is
+-c            to be applied
+-c       w -- array containing all initialization data
+-c
+-c       output:
+-c       y -- the result of applying the random matrix to x
+-c
+-c
+-c        . . . allocate memory
+-c
+-        ialbetas=w(1)
+-        iixs=w(2)
+-        nsteps=w(3)
+-        iww=w(4)
+-        n=w(5)
+-        igammas=w(6)
+-c
+-        call idz_random_transf0(nsteps,x,y,n,w(iww),w(ialbetas),
+-     1      w(igammas),w(iixs))
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idz_random_transf_inverse(x,y,w)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        complex *16 x(*),y(*)
+-        dimension w(*)
+-c
+-c       applies rapidly a random unitary matrix
+-c       to the user-specified vector x,
+-c       using the data in array w stored there by a preceding
+-c       call to routine idz_random_transf_init.
+-c       The transformation applied by the present routine is
+-c       the inverse of the transformation applied
+-c       by routine idz_random_transf.
+-c
+-c       input:
+-c       x -- the vector of length n to which the random matrix is
+-c            to be applied
+-c       w -- array containing all initialization data
+-c
+-c       output:
+-c       y -- the result of applying the random matrix to x
+-c
+-c
+-c        . . . allocate memory
+-c
+-        ialbetas=w(1)
+-        iixs=w(2)
+-        nsteps=w(3)
+-        iww=w(4)
+-        n=w(5)
+-        igammas=w(6)
+-c
+-        call idz_random_transf0_inv(nsteps,x,y,n,w(iww),
+-     1      w(ialbetas),w(igammas),w(iixs))
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idd_random_transf0_inv(nsteps,x,y,n,w2,albetas,iixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension x(*),y(*),w2(*),albetas(2,n,*),iixs(n,*)
+-c
+-c       routine idd_random_transf_inverse serves as a memory wrapper
+-c       for the present routine; see routine idd_random_transf_inverse
+-c       for documentation.
+-c
+-        do 1200 i=1,n
+-c
+-        w2(i)=x(i)
+- 1200 continue
+-c
+-        do 2000 ijk=nsteps,1,-1
+-c
+-        call idd_random_transf00_inv(w2,y,n,albetas(1,1,ijk),
+-     1      iixs(1,ijk) )
+-c
+-        do 1400 j=1,n
+-c
+-        w2(j)=y(j)
+- 1400 continue
+- 2000 continue
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idd_random_transf00_inv(x,y,n,albetas,ixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension x(*),y(*),albetas(2,*),ixs(*)
+-c
+-c       implements one step of the random transform required
+-c       by routine idd_random_transf0_inv (please see the latter).
+-c
+-c
+-c        implement 2 \times 2 matrices
+-c
+-        do 1600 i=1,n
+-        y(i)=x(i)
+- 1600 continue
+-c
+-        do 1800 i=n-1,1,-1
+-c
+-        alpha=albetas(1,i)
+-        beta=albetas(2,i)
+-c
+-        a=y(i)
+-        b=y(i+1)
+-c
+-        y(i)=alpha*a-beta*b
+-        y(i+1)=beta*a+alpha*b
+- 1800 continue
+-c
+-c        implement the permutation
+-c
+-        do 2600 i=1,n
+-c
+-        j=ixs(i)
+-        x(j)=y(i)
+- 2600 continue
+-c
+-        do 2800 i=1,n
+-c
+-        y(i)=x(i)
+- 2800 continue
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idz_random_transf0_inv(nsteps,x,y,n,w2,albetas,
+-     1      gammas,iixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        complex *16 x(*),y(*),w2(*),gammas(n,*)
+-        dimension albetas(2,n,*),iixs(n,*)
+-c
+-c       routine idz_random_transf_inverse serves as a memory wrapper
+-c       for the present routine; please see routine
+-c       idz_random_transf_inverse for documentation.
+-c
+-        do 1200 i=1,n
+-c
+-        w2(i)=x(i)
+- 1200 continue
+-c
+-        do 2000 ijk=nsteps,1,-1
+-c
+-        call idz_random_transf00_inv(w2,y,n,albetas(1,1,ijk),
+-     1      gammas(1,ijk),iixs(1,ijk) )
+-c
+-        do 1400 j=1,n
+-c
+-        w2(j)=y(j)
+- 1400 continue
+- 2000 continue
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idz_random_transf00_inv(x,y,n,albetas,gammas,ixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        complex *16 x(*),y(*),gammas(*),a,b
+-        dimension albetas(2,*),ixs(*)
+-c
+-c       implements one step of the random transform
+-c       required by routine idz_random_transf0_inv
+-c       (please see the latter).
+-c
+-c        implement 2 \times 2 matrices
+-c
+-        do 1600 i=n-1,1,-1
+-c
+-        alpha=albetas(1,i)
+-        beta=albetas(2,i)
+-c
+-        a=x(i)
+-        b=x(i+1)
+-c
+-        x(i)=alpha*a-beta*b
+-        x(i+1)=beta*a+alpha*b
+- 1600 continue
+-c
+-c        implement the permutation
+-c        and divide by the random numbers on the unit circle
+-c        (or, equivalently, multiply by their conjugates)
+-c
+-        do 1800 i=1,n
+-c
+-        j=ixs(i)
+-        y(j)=x(i)*conjg(gammas(i))
+- 1800 continue
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idd_random_transf0(nsteps,x,y,n,w2,albetas,iixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension x(*),y(*),w2(*),albetas(2,n,*),iixs(n,*)
+-c
+-c       routine idd_random_transf serves as a memory wrapper
+-c       for the present routine; please see routine idd_random_transf
+-c       for documentation.
+-c
+-        do 1200 i=1,n
+-c
+-        w2(i)=x(i)
+- 1200 continue
+-c
+-        do 2000 ijk=1,nsteps
+-c
+-        call idd_random_transf00(w2,y,n,albetas(1,1,ijk),iixs(1,ijk) )
+-c
+-        do 1400 j=1,n
+-c
+-        w2(j)=y(j)
+- 1400 continue
+- 2000 continue
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idd_random_transf00(x,y,n,albetas,ixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension x(*),y(*),albetas(2,*),ixs(*)
+-c
+-c       implements one step of the random transform
+-c       required by routine idd_random_transf0 (please see the latter).
+-c
+-c        implement the permutation
+-c
+-        do 1600 i=1,n
+-c
+-        j=ixs(i)
+-        y(i)=x(j)
+- 1600 continue
+-c
+-c        implement 2 \times 2 matrices
+-c
+-        do 1800 i=1,n-1
+-c
+-        alpha=albetas(1,i)
+-        beta=albetas(2,i)
+-c
+-        a=y(i)
+-        b=y(i+1)
+-c
+-        y(i)=alpha*a+beta*b
+-        y(i+1)=-beta*a+alpha*b
+- 1800 continue
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idz_random_transf_init0(nsteps,n,albetas,gammas,ixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension albetas(2,n,*),ixs(n,*)
+-        complex *16 gammas(n,*)
+-c
+-c       routine idz_random_transf_init serves as a memory wrapper
+-c       for the present routine; please see routine
+-c       idz_random_transf_init for documentation.
+-c
+-        do 2000 ijk=1,nsteps
+-c
+-        call idz_random_transf_init00(n,albetas(1,1,ijk),
+-     1      gammas(1,ijk),ixs(1,ijk) )
+- 2000 continue
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idz_random_transf_init00(n,albetas,gammas,ixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension albetas(2,*),gammas(*),ixs(*)
+-c
+-c       constructs one stage of the random transform
+-c       initialized by routine idz_random_transf_init0
+-c       (please see the latter).
+-c
+-        done=1
+-        twopi=2*4*atan(done)
+-c
+-c        construct the random permutation
+-c
+-        ifrepeat=0
+-        call id_randperm(n,ixs)
+-c
+-c        construct the random variables
+-c
+-        call id_srand(2*n,albetas)
+-        call id_srand(2*n,gammas)
+-c
+-        do 1300 i=1,n
+-c
+-        albetas(1,i)=2*albetas(1,i)-1
+-        albetas(2,i)=2*albetas(2,i)-1
+-        gammas(2*i-1)=2*gammas(2*i-1)-1
+-        gammas(2*i)=2*gammas(2*i)-1
+- 1300 continue
+-c
+-c        construct the random 2 \times 2 transformations
+-c
+-        do 1400 i=1,n
+-c
+-        d=albetas(1,i)**2+albetas(2,i)**2
+-        d=1/sqrt(d)
+-        albetas(1,i)=albetas(1,i)*d
+-        albetas(2,i)=albetas(2,i)*d
+- 1400 continue
+-c
+-c        construct the random multipliers on the unit circle
+-c
+-        do 1500 i=1,n
+-c
+-        d=gammas(2*i-1)**2+gammas(2*i)**2
+-        d=1/sqrt(d)
+-c
+-c        fill the real part
+-c
+-        gammas(2*i-1)=gammas(2*i-1)*d
+-c
+-c        fill the imaginary part
+-c
+-        gammas(2*i)=gammas(2*i)*d
+- 1500 continue
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idz_random_transf0(nsteps,x,y,n,w2,albetas,
+-     1      gammas,iixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        complex *16 x(*),y(*),w2(*),gammas(n,*)
+-        dimension albetas(2,n,*),iixs(n,*)
+-c
+-c       routine idz_random_transf serves as a memory wrapper
+-c       for the present routine; please see routine idz_random_transf
+-c       for documentation.
+-c
+-        do 1200 i=1,n
+-c
+-        w2(i)=x(i)
+- 1200 continue
+-c
+-        do 2000 ijk=1,nsteps
+-c
+-        call idz_random_transf00(w2,y,n,albetas(1,1,ijk),
+-     1      gammas(1,ijk),iixs(1,ijk) )
+-        do 1400 j=1,n
+-c
+-        w2(j)=y(j)
+- 1400 continue
+- 2000 continue
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idz_random_transf00(x,y,n,albetas,gammas,ixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        complex *16 x(*),y(*),gammas(*),a,b
+-        dimension albetas(2,*),ixs(*)
+-c
+-c       implements one step of the random transform
+-c       required by routine idz_random_transf0 (please see the latter).
+-c
+-c        implement the permutation
+-c        and multiply by the random numbers
+-c        on the unit circle
+-c
+-        do 1600 i=1,n
+-c
+-        j=ixs(i)
+-        y(i)=x(j)*gammas(i)
+- 1600 continue
+-c
+-c        implement 2 \times 2 matrices
+-c
+-        do 2600 i=1,n-1
+-c
+-        alpha=albetas(1,i)
+-        beta=albetas(2,i)
+-c
+-        a=y(i)
+-        b=y(i+1)
+-c
+-        y(i)=alpha*a+beta*b
+-        y(i+1)=-beta*a+alpha*b
+- 2600 continue
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idd_random_transf_init0(nsteps,n,albetas,ixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension albetas(2,n,*),ixs(n,*)
+-c
+-c       routine idd_random_transf_init serves as a memory wrapper
+-c       for the present routine; please see routine
+-c       idd_random_transf_init for documentation.
+-c
+-        do 2000 ijk=1,nsteps
+-c
+-        call idd_random_transf_init00(n,albetas(1,1,ijk),ixs(1,ijk) )
+- 2000 continue
+-        return
+-        end
+-c
+-c
+-c
+-c
+-c
+-        subroutine idd_random_transf_init00(n,albetas,ixs)
+-        implicit real *8 (a-h,o-z)
+-        save
+-        dimension albetas(2,*),ixs(*)
+-c
+-c       constructs one stage of the random transform
+-c       initialized by routine idd_random_transf_init0
+-c       (please see the latter).
+-c
+-c        construct the random permutation
+-c
+-        ifrepeat=0
+-        call id_randperm(n,ixs)
+-c
+-c        construct the random variables
+-c
+-        call id_srand(2*n,albetas)
+-c
+-        do 1300 i=1,n
+-c
+-        albetas(1,i)=2*albetas(1,i)-1
+-        albetas(2,i)=2*albetas(2,i)-1
+- 1300 continue
+-c
+-c        construct the random 2 \times 2 transformations
+-c
+-        do 1400 i=1,n
+-c
+-        d=albetas(1,i)**2+albetas(2,i)**2
+-        d=1/sqrt(d)
+-        albetas(1,i)=albetas(1,i)*d
+-        albetas(2,i)=albetas(2,i)*d
+- 1400 continue
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idd_frm.f b/scipy/linalg/src/id_dist/src/idd_frm.f
+deleted file mode 100644
+index 0a13112eb..000000000
+--- a/scipy/linalg/src/id_dist/src/idd_frm.f
++++ /dev/null
+@@ -1,525 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idd_frm transforms a vector via a composition
+-c       of Rokhlin's random transform, random subselection, and an FFT.
+-c
+-c       routine idd_sfrm transforms a vector into a vector
+-c       of specified length via a composition
+-c       of Rokhlin's random transform, random subselection, and an FFT.
+-c
+-c       routine idd_frmi initializes routine idd_frm.
+-c
+-c       routine idd_sfrmi initializes routine idd_sfrm.
+-c
+-c       routine idd_pairsamps calculates the indices of the pairs
+-c       of integers to which the individual integers
+-c       in a specified set belong.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idd_frm(m,n,w,x,y)
+-c
+-c       transforms x into y via a composition
+-c       of Rokhlin's random transform, random subselection, and an FFT.
+-c       In contrast to routine idd_sfrm, the present routine works best
+-c       when the length of the transformed vector is the integer n
+-c       output by routine idd_frmi, or when the length
+-c       is not specified, but instead determined a posteriori
+-c       using the output of the present routine. The transformed vector
+-c       output by the present routine is randomly permuted.
+-c
+-c       input:
+-c       m -- length of x
+-c       n -- greatest integer expressible as a positive integer power
+-c            of 2 that is less than or equal to m, as obtained
+-c            from the routine idd_frmi; n is the length of y
+-c       w -- initialization array constructed by routine idd_frmi
+-c       x -- vector to be transformed
+-c
+-c       output:
+-c       y -- transform of x
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,iw,n,k
+-        real*8 w(17*m+70),x(m),y(n)
+-c
+-c
+-c       Apply Rokhlin's random transformation to x, obtaining
+-c       w(16*m+71 : 17*m+70).
+-c
+-        iw = w(3+m+n)
+-        call idd_random_transf(x,w(16*m+70+1),w(iw))
+-c
+-c
+-c       Subselect from  w(16*m+71 : 17*m+70)  to obtain y.
+-c
+-        call idd_subselect(n,w(3),m,w(16*m+70+1),y)
+-c
+-c
+-c       Copy y into  w(16*m+71 : 16*m+n+70).
+-c
+-        do k = 1,n
+-          w(16*m+70+k) = y(k)
+-        enddo ! k
+-c
+-c
+-c       Fourier transform  w(16*m+71 : 16*m+n+70).
+-c
+-        call dfftf(n,w(16*m+70+1),w(4+m+n))
+-c
+-c
+-c       Permute  w(16*m+71 : 16*m+n+70)  to obtain y.
+-c
+-        call idd_permute(n,w(3+m),w(16*m+70+1),y)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_sfrm(l,m,n,w,x,y)
+-c
+-c       transforms x into y via a composition
+-c       of Rokhlin's random transform, random subselection, and an FFT.
+-c       In contrast to routine idd_frm, the present routine works best
+-c       when the length l of the transformed vector is known a priori.
+-c
+-c       input:
+-c       l -- length of y; l must be less than or equal to n
+-c       m -- length of x
+-c       n -- greatest integer expressible as a positive integer power
+-c            of 2 that is less than or equal to m, as obtained
+-c            from the routine idd_sfrmi
+-c       w -- initialization array constructed by routine idd_sfrmi
+-c       x -- vector to be transformed
+-c
+-c       output:
+-c       y -- transform of x
+-c
+-c       _N.B._: l must be less than or equal to n.
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,iw,n,l,l2
+-        real*8 w(27*m+90),x(m),y(l)
+-c
+-c
+-c       Retrieve the number of pairs of outputs to be calculated
+-c       via sfft.
+-c
+-        l2 = w(3)
+-c
+-c
+-c       Apply Rokhlin's random transformation to x, obtaining
+-c       w(25*m+91 : 26*m+90).
+-c
+-        iw = w(4+m+l+l2)
+-        call idd_random_transf(x,w(25*m+90+1),w(iw))
+-c
+-c
+-c       Subselect from  w(25*m+91 : 26*m+90)  to obtain
+-c       w(26*m+91 : 26*m+n+90).
+-c
+-        call idd_subselect(n,w(4),m,w(25*m+90+1),w(26*m+90+1))
+-c
+-c
+-c       Fourier transform  w(26*m+91 : 26*m+n+90).
+-c
+-        call idd_sfft(l2,w(4+m+l),n,w(5+m+l+l2),w(26*m+90+1))
+-c
+-c
+-c       Copy the desired entries from  w(26*m+91 : 26*m+n+90)
+-c       to y.
+-c
+-        call idd_subselect(l,w(4+m),n,w(26*m+90+1),y)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_pairsamps(n,l,ind,l2,ind2,marker)
+-c
+-c       calculates the indices of the l2 pairs of integers
+-c       to which the l individual integers from ind belong.
+-c       The integers in ind may range from 1 to n.
+-c
+-c       input:
+-c       n -- upper bound on the integers in ind
+-c            (the number 1 must be a lower bound);
+-c            n must be even
+-c       l -- length of ind
+-c       ind -- integers selected from 1 to n
+-c
+-c       output:
+-c       l2 -- length of ind2
+-c       ind2 -- indices in the range from 1 to n/2 of the pairs
+-c               of integers to which the entries of ind belong
+-c
+-c       work:
+-c       marker -- must be at least n/2 integer elements long
+-c
+-c       _N.B._: n must be even.
+-c
+-        implicit none
+-        integer l,n,ind(l),ind2(l),marker(n/2),l2,k
+-c
+-c
+-c       Unmark all pairs.
+-c
+-        do k = 1,n/2
+-          marker(k) = 0
+-        enddo ! k
+-c
+-c
+-c       Mark the required pairs.
+-c
+-        do k = 1,l
+-          marker((ind(k)+1)/2) = marker((ind(k)+1)/2)+1
+-        enddo ! k
+-c
+-c
+-c       Record the required pairs in indpair.
+-c
+-        l2 = 0
+-c
+-        do k = 1,n/2
+-c
+-          if(marker(k) .ne. 0) then
+-            l2 = l2+1
+-            ind2(l2) = k
+-          endif
+-c
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_permute(n,ind,x,y)
+-c
+-c       copy the entries of x into y, rearranged according
+-c       to the permutation specified by ind.
+-c
+-c       input:
+-c       n -- length of ind, x, and y
+-c       ind -- permutation of n objects
+-c       x -- vector to be permuted
+-c
+-c       output:
+-c       y -- permutation of x
+-c
+-        implicit none
+-        integer n,ind(n),k
+-        real*8 x(n),y(n)
+-c
+-c
+-        do k = 1,n
+-          y(k) = x(ind(k))
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_subselect(n,ind,m,x,y)
+-c
+-c       copies into y the entries of x indicated by ind.
+-c
+-c       input:
+-c       n -- number of entries of x to copy into y
+-c       ind -- indices of the entries in x to copy into y
+-c       m -- length of x
+-c       x -- vector whose entries are to be copied
+-c
+-c       output:
+-c       y -- collection of entries of x specified by ind
+-c
+-        implicit none
+-        integer n,ind(n),m,k
+-        real*8 x(m),y(n)
+-c
+-c
+-        do k = 1,n
+-          y(k) = x(ind(k))
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_frmi(m,n,w)
+-c
+-c       initializes data for the routine idd_frm.
+-c
+-c       input:
+-c       m -- length of the vector to be transformed
+-c
+-c       output:
+-c       n -- greatest integer expressible as a positive integer power
+-c            of 2 that is less than or equal to m
+-c       w -- initialization array to be used by routine idd_frm
+-c
+-c
+-c       glossary for the fully initialized w:
+-c
+-c       w(1) = m
+-c       w(2) = n
+-c       w(3:2+m) stores a permutation of m objects
+-c       w(3+m:2+m+n) stores a permutation of n objects
+-c       w(3+m+n) = address in w of the initialization array
+-c                  for idd_random_transf
+-c       w(4+m+n:int(w(3+m+n))-1) stores the initialization array
+-c                                for dfft
+-c       w(int(w(3+m+n)):16*m+70) stores the initialization array
+-c                                for idd_random_transf
+-c
+-c
+-c       _N.B._: n is an output of the present routine;
+-c               this routine changes n.
+-c
+-c
+-        implicit none
+-        integer m,n,l,nsteps,keep,lw,ia
+-        real*8 w(17*m+70)
+-c
+-c
+-c       Find the greatest integer less than or equal to m
+-c       which is a power of two.
+-c
+-        call idd_poweroftwo(m,l,n)
+-c
+-c
+-c       Store m and n in w.
+-c
+-        w(1) = m
+-        w(2) = n
+-c
+-c
+-c       Store random permutations of m and n objects in w.
+-c
+-        call id_randperm(m,w(3))
+-        call id_randperm(n,w(3+m))
+-c
+-c
+-c       Store the address within w of the idd_random_transf_init
+-c       initialization data.
+-c
+-        ia = 4+m+n+2*n+15
+-        w(3+m+n) = ia
+-c
+-c
+-c       Store the initialization data for dfft in w.
+-c
+-        call dffti(n,w(4+m+n))
+-c
+-c
+-c       Store the initialization data for idd_random_transf_init in w.
+-c
+-        nsteps = 3
+-        call idd_random_transf_init(nsteps,m,w(ia),keep)
+-c
+-c
+-c       Calculate the total number of elements used in w.
+-c
+-        lw = 3+m+n+2*n+15 + 3*nsteps*m+2*m+m/4+50
+-c
+-        if(16*m+70 .lt. lw) then
+-          call prinf('lw = *',lw,1)
+-          call prinf('16m+70 = *',16*m+70,1)
+-          stop
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_sfrmi(l,m,n,w)
+-c
+-c       initializes data for the routine idd_sfrm.
+-c
+-c       input:
+-c       l -- length of the transformed (output) vector
+-c       m -- length of the vector to be transformed
+-c
+-c       output:
+-c       n -- greatest integer expressible as a positive integer power
+-c            of 2 that is less than or equal to m
+-c       w -- initialization array to be used by routine idd_sfrm
+-c
+-c
+-c       glossary for the fully initialized w:
+-c
+-c       w(1) = m
+-c       w(2) = n
+-c       w(3) = l2
+-c       w(4:3+m) stores a permutation of m objects
+-c       w(4+m:3+m+l) stores the indices of the l outputs which idd_sfft
+-c                    calculates
+-c       w(4+m+l:3+m+l+l2) stores the indices of the l2 pairs of outputs
+-c                         which idd_sfft calculates
+-c       w(4+m+l+l2) = address in w of the initialization array
+-c                     for idd_random_transf
+-c       w(5+m+l+l2:int(w(4+m+l+l2))-1) stores the initialization array
+-c                                      for idd_sfft
+-c       w(int(w(4+m+l+l2)):25*m+90) stores the initialization array
+-c                                   for idd_random_transf
+-c
+-c
+-c       _N.B._: n is an output of the present routine;
+-c               this routine changes n.
+-c
+-c
+-        implicit none
+-        integer l,m,n,idummy,nsteps,keep,lw,l2,ia
+-        real*8 w(27*m+90)
+-c
+-c
+-c       Find the greatest integer less than or equal to m
+-c       which is a power of two.
+-c
+-        call idd_poweroftwo(m,idummy,n)
+-c
+-c
+-c       Store m and n in w.
+-c
+-        w(1) = m
+-        w(2) = n
+-c
+-c
+-c       Store random permutations of m and n objects in w.
+-c
+-        call id_randperm(m,w(4))
+-        call id_randperm(n,w(4+m))
+-c
+-c
+-c       Find the pairs of integers covering the integers in
+-c       w(4+m : 3+m+(l+1)/2).
+-c
+-        call idd_pairsamps(n,l,w(4+m),l2,w(4+m+2*l),w(4+m+3*l))
+-        w(3) = l2
+-        call idd_copyints(l2,w(4+m+2*l),w(4+m+l))
+-c
+-c
+-c       Store the address within w of the idd_random_transf_init
+-c       initialization data.
+-c
+-        ia = 5+m+l+l2+4*l2+30+8*n
+-        w(4+m+l+l2) = ia
+-c
+-c
+-c       Store the initialization data for idd_sfft in w.
+-c
+-        call idd_sffti(l2,w(4+m+l),n,w(5+m+l+l2))
+-c
+-c
+-c       Store the initialization data for idd_random_transf_init in w.
+-c
+-        nsteps = 3
+-        call idd_random_transf_init(nsteps,m,w(ia),keep)
+-c
+-c
+-c       Calculate the total number of elements used in w.
+-c
+-        lw = 4+m+l+l2+4*l2+30+8*n + 3*nsteps*m+2*m+m/4+50
+-c
+-        if(25*m+90 .lt. lw) then
+-          call prinf('lw = *',lw,1)
+-          call prinf('25m+90 = *',25*m+90,1)
+-          stop
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_copyints(n,ia,ib)
+-c
+-c       copies ia into ib.
+-c
+-c       input:
+-c       n -- length of ia and ib
+-c       ia -- array to be copied
+-c
+-c       output:
+-c       ib -- copy of ia
+-c
+-        implicit none
+-        integer n,ia(n),ib(n),k
+-c
+-c
+-        do k = 1,n
+-          ib(k) = ia(k)
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_poweroftwo(m,l,n)
+-c
+-c       computes l = floor(log_2(m)) and n = 2**l.
+-c
+-c       input:
+-c       m -- integer whose log_2 is to be taken
+-c
+-c       output:
+-c       l -- floor(log_2(m))
+-c       n -- 2**l
+-c
+-        implicit none
+-        integer l,m,n
+-c
+-c
+-        l = 0
+-        n = 1
+-c
+- 1000   continue
+-          l = l+1
+-          n = n*2
+-        if(n .le. m) goto 1000
+-c
+-        l = l-1
+-        n = n/2
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idd_house.f b/scipy/linalg/src/id_dist/src/idd_house.f
+deleted file mode 100644
+index 715037117..000000000
+--- a/scipy/linalg/src/id_dist/src/idd_house.f
++++ /dev/null
+@@ -1,288 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idd_house calculates the vector and scalar
+-c       needed to apply the Householder transformation reflecting
+-c       a given vector into its first component.
+-c
+-c       routine idd_houseapp applies a Householder matrix to a vector.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idd_houseapp(n,vn,u,ifrescal,scal,v)
+-c
+-c       applies the Householder matrix
+-c       identity_matrix - scal * vn * transpose(vn)
+-c       to the vector u, yielding the vector v;
+-c
+-c       scal = 2/(1 + vn(2)^2 + ... + vn(n)^2)
+-c       when vn(2), ..., vn(n) don't all vanish;
+-c
+-c       scal = 0
+-c       when vn(2), ..., vn(n) do all vanish
+-c       (including when n = 1).
+-c
+-c       input:
+-c       n -- size of vn, u, and v, though the indexing on vn goes
+-c            from 2 to n
+-c       vn -- components 2 to n of the Householder vector vn;
+-c             vn(1) is assumed to be 1
+-c       u -- vector to be transformed
+-c       ifrescal -- set to 1 to recompute scal from vn(2), ..., vn(n);
+-c                   set to 0 to use scal as input
+-c       scal -- see the entry for ifrescal in the decription
+-c               of the input
+-c
+-c       output:
+-c       scal -- see the entry for ifrescal in the decription
+-c               of the input
+-c       v -- result of applying the Householder matrix to u;
+-c            it's O.K. to have v be the same as u
+-c            in order to apply the matrix to the vector in place
+-c
+-c       reference:
+-c       Golub and Van Loan, "Matrix Computations," 3rd edition,
+-c            Johns Hopkins University Press, 1996, Chapter 5.
+-c
+-        implicit none
+-        save
+-        integer n,k,ifrescal
+-        real*8 vn(2:*),scal,u(n),v(n),fact,sum
+-c
+-c
+-c       Get out of this routine if n = 1.
+-c
+-        if(n .eq. 1) then
+-          v(1) = u(1)
+-          return
+-        endif
+-c
+-c
+-        if(ifrescal .eq. 1) then
+-c
+-c
+-c         Calculate (vn(2))^2 + ... + (vn(n))^2.
+-c
+-          sum = 0
+-          do k = 2,n
+-            sum = sum+vn(k)**2
+-          enddo ! k
+-c
+-c
+-c         Calculate scal.
+-c
+-          if(sum .eq. 0) scal = 0
+-          if(sum .ne. 0) scal = 2/(1+sum)
+-c
+-c
+-        endif
+-c
+-c
+-c       Calculate fact = scal * transpose(vn) * u.
+-c
+-        fact = u(1)
+-c
+-        do k = 2,n
+-          fact = fact+vn(k)*u(k)
+-        enddo ! k
+-c
+-        fact = fact*scal
+-c
+-c
+-c       Subtract fact*vn from u, yielding v.
+-c
+-        v(1) = u(1) - fact
+-c
+-        do k = 2,n
+-          v(k) = u(k) - fact*vn(k)
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_house(n,x,rss,vn,scal)
+-c
+-c       constructs the vector vn with vn(1) = 1
+-c       and the scalar scal such that
+-c       H := identity_matrix - scal * vn * transpose(vn) is orthogonal
+-c       and Hx = +/- e_1 * the root-sum-square of the entries of x
+-c       (H is the Householder matrix corresponding to x).
+-c
+-c       input:
+-c       n -- size of x and vn, though the indexing on vn goes
+-c            from 2 to n
+-c       x -- vector to reflect into its first component
+-c
+-c       output:
+-c       rss -- first entry of the vector resulting from the application
+-c              of the Householder matrix to x;
+-c              its absolute value is the root-sum-square
+-c              of the entries of x
+-c       vn -- entries 2 to n of the Householder vector vn;
+-c             vn(1) is assumed to be 1
+-c       scal -- scalar multiplying vn * transpose(vn);
+-c
+-c               scal = 2/(1 + vn(2)^2 + ... + vn(n)^2)
+-c               when vn(2), ..., vn(n) don't all vanish;
+-c
+-c               scal = 0
+-c               when vn(2), ..., vn(n) do all vanish
+-c               (including when n = 1)
+-c
+-c       reference:
+-c       Golub and Van Loan, "Matrix Computations," 3rd edition,
+-c            Johns Hopkins University Press, 1996, Chapter 5.
+-c
+-        implicit none
+-        save
+-        integer n,k
+-        real*8 x(n),rss,sum,v1,scal,vn(2:*),x1
+-c
+-c
+-        x1 = x(1)
+-c
+-c
+-c       Get out of this routine if n = 1.
+-c
+-        if(n .eq. 1) then
+-          rss = x1
+-          scal = 0
+-          return
+-        endif
+-c
+-c
+-c       Calculate (x(2))^2 + ... (x(n))^2
+-c       and the root-sum-square value of the entries in x.
+-c
+-c
+-        sum = 0
+-        do k = 2,n
+-          sum = sum+x(k)**2
+-        enddo ! k
+-c
+-c
+-c       Get out of this routine if sum = 0;
+-c       flag this case as such by setting v(2), ..., v(n) all to 0.
+-c
+-        if(sum .eq. 0) then
+-c
+-          rss = x1
+-          do k = 2,n
+-            vn(k) = 0
+-          enddo ! k
+-          scal = 0
+-c
+-          return
+-c
+-        endif
+-c
+-c
+-        rss = x1**2 + sum
+-        rss = sqrt(rss)
+-c
+-c
+-c       Determine the first component v1
+-c       of the unnormalized Householder vector
+-c       v = x - rss * (1 0 0 ... 0 0)^T.
+-c
+-c       If x1 <= 0, then form x1-rss directly,
+-c       since that expression cannot involve any cancellation.
+-c
+-        if(x1 .le. 0) v1 = x1-rss
+-c
+-c       If x1 > 0, then use the fact that
+-c       x1-rss = -sum / (x1+rss),
+-c       in order to avoid potential cancellation.
+-c
+-        if(x1 .gt. 0) v1 = -sum / (x1+rss)
+-c
+-c
+-c       Compute the vector vn and the scalar scal such that vn(1) = 1
+-c       in the Householder transformation
+-c       identity_matrix - scal * vn * transpose(vn).
+-c
+-        do k = 2,n
+-          vn(k) = x(k)/v1
+-        enddo ! k
+-c
+-c       scal = 2
+-c            / ( vn(1)^2 + vn(2)^2 + ... + vn(n)^2 )
+-c
+-c            = 2
+-c            / ( 1 + vn(2)^2 + ... + vn(n)^2 )
+-c
+-c            = 2*v(1)^2
+-c            / ( v(1)^2 + (v(1)*vn(2))^2 + ... + (v(1)*vn(n))^2 )
+-c
+-c            = 2*v(1)^2
+-c            / ( v(1)^2 + (v(2)^2 + ... + v(n)^2) )
+-c
+-        scal = 2*v1**2 / (v1**2+sum)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_housemat(n,vn,scal,h)
+-c
+-c       fills h with the Householder matrix
+-c       identity_matrix - scal * vn * transpose(vn).
+-c
+-c       input:
+-c       n -- size of vn and h, though the indexing of vn goes
+-c            from 2 to n
+-c       vn -- entries 2 to n of the vector vn;
+-c             vn(1) is assumed to be 1
+-c       scal -- scalar multiplying vn * transpose(vn)
+-c
+-c       output:
+-c       h -- identity_matrix - scal * vn * transpose(vn)
+-c
+-        implicit none
+-        save
+-        integer n,j,k
+-        real*8 vn(2:*),h(n,n),scal,factor1,factor2
+-c
+-c
+-c       Fill h with the identity matrix.
+-c
+-        do j = 1,n
+-          do k = 1,n
+-c
+-            if(j .eq. k) h(k,j) = 1
+-            if(j .ne. k) h(k,j) = 0
+-c
+-          enddo ! k
+-        enddo ! j
+-c
+-c
+-c       Subtract from h the matrix scal*vn*transpose(vn).
+-c
+-        do j = 1,n
+-          do k = 1,n
+-c
+-            if(j .eq. 1) factor1 = 1
+-            if(j .ne. 1) factor1 = vn(j)
+-c
+-            if(k .eq. 1) factor2 = 1
+-            if(k .ne. 1) factor2 = vn(k)
+-c
+-            h(k,j) = h(k,j) - scal*factor1*factor2
+-c
+-          enddo ! k
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idd_id.f b/scipy/linalg/src/id_dist/src/idd_id.f
+deleted file mode 100644
+index 640ff455b..000000000
+--- a/scipy/linalg/src/id_dist/src/idd_id.f
++++ /dev/null
+@@ -1,560 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddp_id computes the ID of a matrix,
+-c       to a specified precision.
+-c
+-c       routine iddr_id computes the ID of a matrix,
+-c       to a specified rank.
+-c
+-c       routine idd_reconid reconstructs a matrix from its ID.
+-c
+-c       routine idd_copycols collects together selected columns
+-c       of a matrix.
+-c
+-c       routine idd_getcols collects together selected columns
+-c       of a matrix specified by a routine for applying the matrix
+-c       to arbitrary vectors.
+-c
+-c       routine idd_reconint constructs p in the ID a = b p,
+-c       where the columns of b are a subset of the columns of a,
+-c       and p is the projection coefficient matrix,
+-c       given list, krank, and proj output by routines iddr_id
+-c       or iddp_id.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine iddp_id(eps,m,n,a,krank,list,rnorms)
+-c
+-c       computes the ID of a, i.e., lists in list the indices
+-c       of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                        krank
+-c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
+-c                         l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon dimensioned epsilon(m,n-krank)
+-c       such that the greatest singular value of epsilon
+-c       <= the greatest singular value of a * eps.
+-c       The present routine stores the krank x (n-krank) matrix proj
+-c       in the memory initially occupied by a.
+-c
+-c       input:
+-c       eps -- relative precision of the resulting ID
+-c       m -- first dimension of a
+-c       n -- second dimension of a, as well as the dimension required
+-c            of list
+-c       a -- matrix to be ID'd
+-c
+-c       output:
+-c       a -- the first krank*(n-krank) elements of a constitute
+-c            the krank x (n-krank) interpolation matrix proj
+-c       krank -- numerical rank
+-c       list -- list of the indices of the krank columns of a
+-c               through which the other columns of a are expressed;
+-c               also, list describes the permutation of proj
+-c               required to reconstruct a as indicated in (*) above
+-c       rnorms -- absolute values of the entries on the diagonal
+-c                 of the triangular matrix used to compute the ID
+-c                 (these may be used to check the stability of the ID)
+-c
+-c       _N.B._: This routine changes a.
+-c
+-c       reference:
+-c       Cheng, Gimbutas, Martinsson, Rokhlin, "On the compression of
+-c            low-rank matrices," SIAM Journal on Scientific Computing,
+-c            26 (4): 1389-1404, 2005.
+-c
+-        implicit none
+-        integer m,n,krank,k,list(n),iswap
+-        real*8 a(m,n),eps,rnorms(n)
+-c
+-c
+-c       QR decompose a.
+-c
+-        call iddp_qrpiv(eps,m,n,a,krank,list,rnorms)
+-c
+-c
+-c       Build the list of columns chosen in a
+-c       by multiplying together the permutations in list,
+-c       with the permutation swapping 1 and list(1) taken rightmost
+-c       in the product, that swapping 2 and list(2) taken next
+-c       rightmost, ..., that swapping krank and list(krank) taken
+-c       leftmost.
+-c
+-        do k = 1,n
+-          rnorms(k) = k
+-        enddo ! k
+-c
+-        if(krank .gt. 0) then
+-          do k = 1,krank
+-c
+-c           Swap rnorms(k) and rnorms(list(k)).
+-c
+-            iswap = rnorms(k)
+-            rnorms(k) = rnorms(list(k))
+-            rnorms(list(k)) = iswap
+-c
+-          enddo ! k
+-        endif
+-c
+-        do k = 1,n
+-          list(k) = rnorms(k)
+-        enddo ! k
+-c
+-c
+-c       Fill rnorms for the output.
+-c
+-        if(krank .gt. 0) then
+-c
+-          do k = 1,krank
+-            rnorms(k) = a(k,k)
+-          enddo ! k
+-c
+-        endif
+-c
+-c
+-c       Backsolve for proj, storing it at the beginning of a.
+-c
+-        if(krank .gt. 0) then
+-          call idd_lssolve(m,n,a,krank)
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddr_id(m,n,a,krank,list,rnorms)
+-c
+-c       computes the ID of a, i.e., lists in list the indices
+-c       of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                        krank
+-c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
+-c                         l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
+-c       whose norm is (hopefully) minimized by the pivoting procedure.
+-c       The present routine stores the krank x (n-krank) matrix proj
+-c       in the memory initially occupied by a.
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a, as well as the dimension required
+-c            of list
+-c       a -- matrix to be ID'd
+-c       krank -- desired rank of the output matrix
+-c                (please note that if krank > m or krank > n,
+-c                then the rank of the output matrix will be
+-c                less than krank)
+-c
+-c       output:
+-c       a -- the first krank*(n-krank) elements of a constitute
+-c            the krank x (n-krank) interpolation matrix proj
+-c       list -- list of the indices of the krank columns of a
+-c               through which the other columns of a are expressed;
+-c               also, list describes the permutation of proj
+-c               required to reconstruct a as indicated in (*) above
+-c       rnorms -- absolute values of the entries on the diagonal
+-c                 of the triangular matrix used to compute the ID
+-c                 (these may be used to check the stability of the ID)
+-c
+-c       _N.B._: This routine changes a.
+-c
+-c       reference:
+-c       Cheng, Gimbutas, Martinsson, Rokhlin, "On the compression of
+-c            low-rank matrices," SIAM Journal on Scientific Computing,
+-c            26 (4): 1389-1404, 2005.
+-c
+-        implicit none
+-        integer m,n,krank,j,k,list(n),iswap
+-        real*8 a(m,n),rnorms(n),ss
+-c
+-c
+-c       QR decompose a.
+-c
+-        call iddr_qrpiv(m,n,a,krank,list,rnorms)
+-c
+-c
+-c       Build the list of columns chosen in a
+-c       by multiplying together the permutations in list,
+-c       with the permutation swapping 1 and list(1) taken rightmost
+-c       in the product, that swapping 2 and list(2) taken next
+-c       rightmost, ..., that swapping krank and list(krank) taken
+-c       leftmost.
+-c
+-        do k = 1,n
+-          rnorms(k) = k
+-        enddo ! k
+-c
+-        if(krank .gt. 0) then
+-          do k = 1,krank
+-c
+-c           Swap rnorms(k) and rnorms(list(k)).
+-c
+-            iswap = rnorms(k)
+-            rnorms(k) = rnorms(list(k))
+-            rnorms(list(k)) = iswap
+-c
+-          enddo ! k
+-        endif
+-c
+-        do k = 1,n
+-          list(k) = rnorms(k)
+-        enddo ! k
+-c
+-c
+-c       Fill rnorms for the output.
+-c
+-        ss = 0
+-c
+-        do k = 1,krank
+-          rnorms(k) = a(k,k)
+-          ss = ss+rnorms(k)**2
+-        enddo ! k
+-c
+-c
+-c       Backsolve for proj, storing it at the beginning of a.
+-c
+-        if(krank .gt. 0 .and. ss .gt. 0) then
+-          call idd_lssolve(m,n,a,krank)
+-        endif
+-c
+-        if(ss .eq. 0) then
+-c
+-          do k = 1,n
+-            do j = 1,m
+-c
+-              a(j,k) = 0
+-c
+-            enddo ! j
+-          enddo ! k
+-c
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_reconid(m,krank,col,n,list,proj,approx)
+-c
+-c       reconstructs the matrix that the routine iddp_id
+-c       or iddr_id has decomposed, using the columns col
+-c       of the reconstructed matrix whose indices are listed in list,
+-c       in addition to the interpolation matrix proj.
+-c
+-c       input:
+-c       m -- first dimension of cols and approx
+-c       krank -- first dimension of cols and proj; also,
+-c                n-krank is the second dimension of proj
+-c       col -- columns of the matrix to be reconstructed
+-c       n -- second dimension of approx; also,
+-c            n-krank is the second dimension of proj
+-c       list(k) -- index of col(1:m,k) in the reconstructed matrix
+-c                  when k <= krank; in general, list describes
+-c                  the permutation required for reconstruction
+-c                  via cols and proj
+-c       proj -- interpolation matrix
+-c
+-c       output:
+-c       approx -- reconstructed matrix
+-c
+-        implicit none
+-        integer m,n,krank,j,k,l,list(n)
+-        real*8 col(m,krank),proj(krank,n-krank),approx(m,n)
+-c
+-c
+-        do j = 1,m
+-          do k = 1,n
+-c
+-            approx(j,list(k)) = 0
+-c
+-c           Add in the contributions due to the identity matrix.
+-c
+-            if(k .le. krank) then
+-              approx(j,list(k)) = approx(j,list(k)) + col(j,k)
+-            endif
+-c
+-c           Add in the contributions due to proj.
+-c
+-            if(k .gt. krank) then
+-              if(krank .gt. 0) then
+-c
+-                do l = 1,krank
+-                  approx(j,list(k)) = approx(j,list(k))
+-     1                              + col(j,l)*proj(l,k-krank)
+-                enddo ! l
+-c
+-              endif
+-            endif
+-c
+-          enddo ! k
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_lssolve(m,n,a,krank)
+-c
+-c       backsolves for proj satisfying R_11 proj ~ R_12,
+-c       where R_11 = a(1:krank,1:krank)
+-c       and R_12 = a(1:krank,krank+1:n).
+-c       This routine overwrites the beginning of a with proj.
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a; also,
+-c            n-krank is the second dimension of proj
+-c       a -- trapezoidal input matrix
+-c       krank -- first dimension of proj; also,
+-c                n-krank is the second dimension of proj
+-c
+-c       output:
+-c       a -- the first krank*(n-krank) elements of a constitute
+-c            the krank x (n-krank) matrix proj
+-c
+-        implicit none
+-        integer m,n,krank,j,k,l
+-        real*8 a(m,n),sum
+-c
+-c
+-c       Overwrite a(1:krank,krank+1:n) with proj.
+-c
+-        do k = 1,n-krank
+-          do j = krank,1,-1
+-c
+-            sum = 0
+-c
+-            do l = j+1,krank
+-              sum = sum+a(j,l)*a(l,krank+k)
+-            enddo ! l
+-c
+-            a(j,krank+k) = a(j,krank+k)-sum
+-c
+-c           Make sure that the entry in proj won't be too big;
+-c           set the entry to 0 when roundoff would make it too big
+-c           (in which case a(j,j) is so small that the contribution
+-c           from this entry in proj to the overall matrix approximation
+-c           is supposed to be negligible).
+-c
+-            if(abs(a(j,krank+k)) .lt. 2**20*abs(a(j,j))) then
+-              a(j,krank+k) = a(j,krank+k)/a(j,j)
+-            else
+-              a(j,krank+k) = 0
+-            endif
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-c       Move proj from a(1:krank,krank+1:n) to the beginning of a.
+-c
+-        call idd_moverup(m,n,krank,a)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_moverup(m,n,krank,a)
+-c
+-c       moves the krank x (n-krank) matrix in a(1:krank,krank+1:n),
+-c       where a is initially dimensioned m x n, to the beginning of a.
+-c       (This is not the most natural way to code the move,
+-c       but one of my usually well-behaved compilers chokes
+-c       on more natural ways.)
+-c
+-c       input:
+-c       m -- initial first dimension of a
+-c       n -- initial second dimension of a
+-c       krank -- number of rows to move
+-c       a -- m x n matrix whose krank x (n-krank) block
+-c            a(1:krank,krank+1:n) is to be moved
+-c
+-c       output:
+-c       a -- array starting with the moved krank x (n-krank) block
+-c
+-        implicit none
+-        integer m,n,krank,j,k
+-        real*8 a(m*n)
+-c
+-c
+-        do k = 1,n-krank
+-          do j = 1,krank
+-            a(j+krank*(k-1)) = a(j+m*(krank+k-1))
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,
+-     1                         col,x)
+-c
+-c       collects together the columns of the matrix a indexed by list
+-c       into the matrix col, where routine matvec applies a
+-c       to an arbitrary vector.
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       matvec -- routine which applies a to an arbitrary vector;
+-c                 this routine must have a calling sequence of the form
+-c
+-c                 matvec(m,x,n,y,p1,p2,p3,p4)
+-c
+-c                 where m is the length of x,
+-c                 x is the vector to which the matrix is to be applied,
+-c                 n is the length of y,
+-c                 y is the product of the matrix and x,
+-c                 and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvec
+-c       p2 -- parameter to be passed to routine matvec
+-c       p3 -- parameter to be passed to routine matvec
+-c       p4 -- parameter to be passed to routine matvec
+-c       krank -- number of columns to be extracted
+-c       list -- indices of the columns to be extracted
+-c
+-c       output:
+-c       col -- columns of a indexed by list
+-c
+-c       work:
+-c       x -- must be at least n real*8 elements long
+-c
+-        implicit none
+-        integer m,n,krank,list(krank),j,k
+-        real*8 col(m,krank),x(n),p1,p2,p3,p4
+-        external matvec
+-c
+-c
+-        do j = 1,krank
+-c
+-          do k = 1,n
+-            x(k) = 0
+-          enddo ! k
+-c
+-          x(list(j)) = 1
+-c
+-          call matvec(n,x,m,col(1,j),p1,p2,p3,p4)
+-c
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_reconint(n,list,krank,proj,p)
+-c
+-c       constructs p in the ID a = b p,
+-c       where the columns of b are a subset of the columns of a,
+-c       and p is the projection coefficient matrix,
+-c       given list, krank, and proj output
+-c       by routines iddp_id or iddr_id.
+-c
+-c       input:
+-c       n -- part of the second dimension of proj and p
+-c       list -- list of columns retained from the original matrix
+-c               in the ID
+-c       krank -- rank of the ID
+-c       proj -- matrix of projection coefficients in the ID
+-c
+-c       output:
+-c       p -- projection matrix in the ID
+-c
+-        implicit none
+-        integer n,krank,list(n),j,k
+-        real*8 proj(krank,n-krank),p(krank,n)
+-c
+-c
+-        do k = 1,krank
+-          do j = 1,n
+-c
+-            if(j .le. krank) then
+-              if(j .eq. k) p(k,list(j)) = 1
+-              if(j .ne. k) p(k,list(j)) = 0
+-            endif
+-c
+-            if(j .gt. krank) then
+-              p(k,list(j)) = proj(k,j-krank)
+-            endif
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_copycols(m,n,a,krank,list,col)
+-c
+-c       collects together the columns of the matrix a indexed by list
+-c       into the matrix col.
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       a -- matrix whose columns are to be extracted
+-c       krank -- number of columns to be extracted
+-c       list -- indices of the columns to be extracted
+-c
+-c       output:
+-c       col -- columns of a indexed by list
+-c
+-        implicit none
+-        integer m,n,krank,list(krank),j,k
+-        real*8 a(m,n),col(m,krank)
+-c
+-c
+-        do k = 1,krank
+-          do j = 1,m
+-c
+-            col(j,k) = a(j,list(k))
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idd_id2svd.f b/scipy/linalg/src/id_dist/src/idd_id2svd.f
+deleted file mode 100644
+index 42e1f23cd..000000000
+--- a/scipy/linalg/src/id_dist/src/idd_id2svd.f
++++ /dev/null
+@@ -1,384 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idd_id2svd converts an approximation to a matrix
+-c       in the form of an ID to an approximation in the form of an SVD.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idd_id2svd(m,krank,b,n,list,proj,u,v,s,ier,w)
+-c
+-c       converts an approximation to a matrix in the form of an ID
+-c       to an approximation in the form of an SVD.
+-c
+-c       input:
+-c       m -- first dimension of b
+-c       krank -- rank of the ID
+-c       b -- columns of the original matrix in the ID
+-c       list -- list of columns chosen from the original matrix
+-c               in the ID
+-c       n -- length of list and part of the second dimension of proj
+-c       proj -- projection coefficients in the ID
+-c
+-c       output:
+-c       u -- left singular vectors
+-c       v -- right singular vectors
+-c       s -- singular values
+-c       ier -- 0 when the routine terminates successfully;
+-c              nonzero otherwise
+-c
+-c       work:
+-c       w -- must be at least (krank+1)*(m+3*n)+26*krank**2 real*8
+-c            elements long
+-c
+-c       _N.B._: This routine destroys b.
+-c
+-        implicit none
+-        integer m,krank,n,list(n),iwork,lwork,ip,lp,it,lt,ir,lr,
+-     1          ir2,lr2,ir3,lr3,iind,lind,iindt,lindt,lw,ier
+-        real*8 b(m,krank),proj(krank,n-krank),u(m,krank),v(n,krank),
+-     1         w((krank+1)*(m+3*n)+26*krank**2),s(krank)
+-c
+-c
+-        lw = 0
+-c
+-        iwork = lw+1
+-        lwork = 25*krank**2
+-        lw = lw+lwork
+-c
+-        ip = lw+1
+-        lp = krank*n
+-        lw = lw+lp
+-c
+-        it = lw+1
+-        lt = n*krank
+-        lw = lw+lt
+-c
+-        ir = lw+1
+-        lr = krank*n
+-        lw = lw+lr
+-c
+-        ir2 = lw+1
+-        lr2 = krank*m
+-        lw = lw+lr2
+-c
+-        ir3 = lw+1
+-        lr3 = krank*krank
+-        lw = lw+lr3
+-c
+-        iind = lw+1
+-        lind = n/2+1
+-        lw = lw+1
+-c
+-        iindt = lw+1
+-        lindt = m/2+1
+-        lw = lw+1
+-c
+-c
+-        call idd_id2svd0(m,krank,b,n,list,proj,u,v,s,ier,
+-     1                   w(iwork),w(ip),w(it),w(ir),w(ir2),w(ir3),
+-     2                   w(iind),w(iindt))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_id2svd0(m,krank,b,n,list,proj,u,v,s,ier,
+-     1                         work,p,t,r,r2,r3,ind,indt)
+-c
+-c       routine idd_id2svd serves as a memory wrapper
+-c       for the present routine (please see routine idd_id2svd
+-c       for further documentation).
+-c
+-        implicit none
+-c
+-        character*1 jobz
+-        integer m,n,krank,list(n),ind(n),indt(m),iftranspose,
+-     1          lwork,ldu,ldvt,ldr,info,j,k,ier
+-        real*8 b(m,krank),proj(krank,n-krank),p(krank,n),
+-     1         r(krank,n),r2(krank,m),t(n,krank),r3(krank,krank),
+-     2         u(m,krank),v(n,krank),s(krank),work(25*krank**2)
+-c
+-c
+-c
+-        ier = 0
+-c
+-c
+-c
+-c       Construct the projection matrix p from the ID.
+-c
+-        call idd_reconint(n,list,krank,proj,p)
+-c
+-c
+-c
+-c       Compute a pivoted QR decomposition of b.
+-c
+-        call iddr_qrpiv(m,krank,b,krank,ind,r)
+-c
+-c
+-c       Extract r from the QR decomposition.
+-c
+-        call idd_rinqr(m,krank,b,krank,r)
+-c
+-c
+-c       Rearrange r according to ind.
+-c
+-        call idd_rearr(krank,ind,krank,krank,r)
+-c
+-c
+-c
+-c       Transpose p to obtain t.
+-c
+-        call idd_mattrans(krank,n,p,t)
+-c
+-c
+-c       Compute a pivoted QR decomposition of t.
+-c
+-        call iddr_qrpiv(n,krank,t,krank,indt,r2)
+-c
+-c
+-c       Extract r2 from the QR decomposition.
+-c
+-        call idd_rinqr(n,krank,t,krank,r2)
+-c
+-c
+-c       Rearrange r2 according to indt.
+-c
+-        call idd_rearr(krank,indt,krank,krank,r2)
+-c
+-c
+-c
+-c       Multiply r and r2^T to obtain r3.
+-c
+-        call idd_matmultt(krank,krank,r,krank,r2,r3)
+-c
+-c
+-c
+-c       Use LAPACK to SVD r3.
+-c
+-        jobz = 'S'
+-        ldr = krank
+-        lwork = 25*krank**2-krank**2-4*krank
+-        ldu = krank
+-        ldvt = krank
+-c
+-        call dgesdd(jobz,krank,krank,r3,ldr,s,work,ldu,r,ldvt,
+-     1              work(krank**2+4*krank+1),lwork,
+-     2              work(krank**2+1),info)
+-c
+-        if(info .ne. 0) then
+-          ier = info
+-          return
+-        endif
+-c
+-c
+-c
+-c       Multiply the u from r3 from the left by the q from b
+-c       to obtain the u for a.
+-c
+-        do k = 1,krank
+-c
+-          do j = 1,krank
+-            u(j,k) = work(j+krank*(k-1))
+-          enddo ! j
+-c
+-          do j = krank+1,m
+-            u(j,k) = 0
+-          enddo ! j
+-c
+-        enddo ! k
+-c
+-        iftranspose = 0
+-        call idd_qmatmat(iftranspose,m,krank,b,krank,krank,u,r2)
+-c
+-c
+-c
+-c       Transpose r to obtain r2.
+-c
+-        call idd_mattrans(krank,krank,r,r2)
+-c
+-c
+-c       Multiply the v from r3 from the left by the q from p^T
+-c       to obtain the v for a.
+-c
+-        do k = 1,krank
+-c
+-          do j = 1,krank
+-            v(j,k) = r2(j,k)
+-          enddo ! j
+-c
+-          do j = krank+1,n
+-            v(j,k) = 0
+-          enddo ! j
+-c
+-        enddo ! k
+-c
+-        iftranspose = 0
+-        call idd_qmatmat(iftranspose,n,krank,t,krank,krank,v,r2)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_mattrans(m,n,a,at)
+-c
+-c       transposes a to obtain at.
+-c
+-c       input:
+-c       m -- first dimension of a, and second dimension of at
+-c       n -- second dimension of a, and first dimension of at
+-c       a -- matrix to be transposed
+-c
+-c       output:
+-c       at -- transpose of a
+-c
+-        implicit none
+-        integer m,n,j,k
+-        real*8 a(m,n),at(n,m)
+-c
+-c
+-        do k = 1,n
+-          do j = 1,m
+-            at(k,j) = a(j,k)
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_matmultt(l,m,a,n,b,c)
+-c
+-c       multiplies a and b^T to obtain c.
+-c
+-c       input:
+-c       l -- first dimension of a and c
+-c       m -- second dimension of a and b
+-c       a -- leftmost matrix in the product c = a b^T
+-c       n -- first dimension of b and second dimension of c
+-c       b -- rightmost matrix in the product c = a b^T
+-c
+-c       output:
+-c       c -- product of a and b^T
+-c
+-        implicit none
+-        integer l,m,n,i,j,k
+-        real*8 a(l,m),b(n,m),c(l,n),sum
+-c
+-c
+-        do i = 1,l
+-          do k = 1,n
+-c
+-            sum = 0
+-c
+-            do j = 1,m
+-              sum = sum+a(i,j)*b(k,j)
+-            enddo ! j
+-c
+-            c(i,k) = sum
+-c
+-          enddo ! k
+-        enddo ! i
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_rearr(krank,ind,m,n,a)
+-c
+-c       rearranges a according to ind obtained
+-c       from routines iddr_qrpiv or iddp_qrpiv,
+-c       assuming that a = q r, where q and r are from iddr_qrpiv
+-c       or iddp_qrpiv.
+-c
+-c       input:
+-c       krank -- rank obtained from routine iddp_qrpiv,
+-c                or provided to routine iddr_qrpiv
+-c       ind -- indexing array obtained from routine iddr_qrpiv
+-c              or iddp_qrpiv
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       a -- matrix to be rearranged
+-c
+-c       output:
+-c       a -- rearranged matrix
+-c
+-        implicit none
+-        integer k,krank,m,n,j,ind(krank)
+-        real*8 rswap,a(m,n)
+-c
+-c
+-        do k = krank,1,-1
+-          do j = 1,m
+-c
+-            rswap = a(j,k)
+-            a(j,k) = a(j,ind(k))
+-            a(j,ind(k)) = rswap
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_rinqr(m,n,a,krank,r)
+-c
+-c       extracts R in the QR decomposition specified by the output a
+-c       of the routine iddr_qrpiv or iddp_qrpiv.
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a and r
+-c       a -- output of routine iddr_qrpiv or iddp_qrpiv
+-c       krank -- rank output by routine iddp_qrpiv (or specified
+-c                to routine iddr_qrpiv)
+-c
+-c       output:
+-c       r -- triangular factor in the QR decomposition specified
+-c            by the output a of the routine iddr_qrpiv or iddp_qrpiv
+-c
+-        implicit none
+-        integer m,n,j,k,krank
+-        real*8 a(m,n),r(krank,n)
+-c
+-c
+-c       Copy a into r and zero out the appropriate
+-c       Householder vectors that are stored in one triangle of a.
+-c
+-        do k = 1,n
+-          do j = 1,krank
+-            r(j,k) = a(j,k)
+-          enddo ! j
+-        enddo ! k
+-c
+-        do k = 1,n
+-          if(k .lt. krank) then
+-            do j = k+1,krank
+-              r(j,k) = 0
+-            enddo ! j
+-          endif
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idd_qrpiv.f b/scipy/linalg/src/id_dist/src/idd_qrpiv.f
+deleted file mode 100644
+index b1dd88e15..000000000
+--- a/scipy/linalg/src/id_dist/src/idd_qrpiv.f
++++ /dev/null
+@@ -1,893 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddp_qrpiv computes the pivoted QR decomposition
+-c       of a matrix via Householder transformations,
+-c       stopping at a specified precision of the decomposition.
+-c
+-c       routine iddr_qrpiv computes the pivoted QR decomposition
+-c       of a matrix via Householder transformations,
+-c       stopping at a specified rank of the decomposition.
+-c
+-c       routine idd_qmatvec applies to a single vector
+-c       the Q matrix (or its transpose) in the QR decomposition
+-c       of a matrix, as described by the output of iddp_qrpiv
+-c       or iddr_qrpiv. If you're concerned about efficiency
+-c       and want to apply Q (or its transpose) to multiple vectors,
+-c       use idd_qmatmat instead.
+-c
+-c       routine idd_qmatmat applies
+-c       to multiple vectors collected together
+-c       as a matrix the Q matrix (or its transpose)
+-c       in the QR decomposition of a matrix, as described
+-c       by the output of iddp_qrpiv or iddr_qrpiv. If you don't want
+-c       to provide a work array and want to apply Q (or its transpose)
+-c       to a single vector, use idd_qmatvec instead.
+-c
+-c       routine idd_qinqr reconstructs the Q matrix
+-c       in a QR decomposition from the data generated
+-c       by iddp_qrpiv or iddr_qrpiv.
+-c
+-c       routine idd_permmult multiplies together a bunch
+-c       of permutations.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-
+-        subroutine idd_permmult(m,ind,n,indprod)
+-c
+-c       multiplies together the series of permutations in ind.
+-c
+-c       input:
+-c       m -- length of ind
+-c       ind(k) -- number of the slot with which to swap
+-c                 the k^th slot
+-c       n -- length of indprod and indprodinv
+-c
+-c       output:
+-c       indprod -- product of the permutations in ind,
+-c                  with the permutation swapping 1 and ind(1)
+-c                  taken leftmost in the product,
+-c                  that swapping 2 and ind(2) taken next leftmost,
+-c                  ..., that swapping krank and ind(krank)
+-c                  taken rightmost; indprod(k) is the number
+-c                  of the slot with which to swap the k^th slot
+-c                  in the product permutation
+-c
+-        implicit none
+-        integer m,n,ind(m),indprod(n),k,iswap
+-c
+-c
+-        do k = 1,n
+-          indprod(k) = k
+-        enddo ! k
+-c
+-        do k = m,1,-1
+-c
+-c         Swap indprod(k) and indprod(ind(k)).
+-c
+-          iswap = indprod(k)
+-          indprod(k) = indprod(ind(k))
+-          indprod(ind(k)) = iswap
+-c
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_qinqr(m,n,a,krank,q)
+-c
+-c       constructs the matrix q from iddp_qrpiv or iddr_qrpiv
+-c       (see the routine iddp_qrpiv or iddr_qrpiv
+-c       for more information).
+-c
+-c       input:
+-c       m -- first dimension of a; also, right now, q is m x m
+-c       n -- second dimension of a
+-c       a -- matrix output by iddp_qrpiv or iddr_qrpiv
+-c            (and denoted the same there)
+-c       krank -- numerical rank output by iddp_qrpiv or iddr_qrpiv
+-c                (and denoted the same there)
+-c
+-c       output:
+-c       q -- orthogonal matrix implicitly specified by the data in a
+-c            from iddp_qrpiv or iddr_qrpiv
+-c
+-c       Note:
+-c       Right now, this routine simply multiplies
+-c       one after another the krank Householder matrices
+-c       in the full QR decomposition of a,
+-c       in order to obtain the complete m x m Q factor in the QR.
+-c       This routine should instead use the following
+-c       (more elaborate but more efficient) scheme
+-c       to construct a q dimensioned q(krank,m); this scheme
+-c       was introduced by Robert Schreiber and Charles Van Loan
+-c       in "A Storage-Efficient _WY_ Representation
+-c       for Products of Householder Transformations,"
+-c       _SIAM Journal on Scientific and Statistical Computing_,
+-c       Vol. 10, No. 1, pp. 53-57, January, 1989:
+-c
+-c       Theorem 1. Suppose that Q = _1_ + YTY^T is
+-c       an m x m orthogonal real matrix,
+-c       where Y is an m x k real matrix
+-c       and T is a k x k upper triangular real matrix.
+-c       Suppose also that P = _1_ - 2 v v^T is
+-c       a real Householder matrix and Q_+ = QP,
+-c       where v is an m x 1 real vector,
+-c       normalized so that v^T v = 1.
+-c       Then, Q_+ = _1_ + Y_+ T_+ Y_+^T,
+-c       where Y_+ = (Y v) is the m x (k+1) matrix
+-c       formed by adjoining v to the right of Y,
+-c                 ( T   z )
+-c       and T_+ = (       ) is
+-c                 ( 0  -2 )
+-c       the (k+1) x (k+1) upper triangular matrix
+-c       formed by adjoining z to the right of T
+-c       and the vector (0 ... 0 -2) with k zeroes below (T z),
+-c       where z = -2 T Y^T v.
+-c
+-c       Now, suppose that A is a (rank-deficient) matrix
+-c       whose complete QR decomposition has
+-c       the blockwise partioned form
+-c           ( Q_11 Q_12 ) ( R_11 R_12 )   ( Q_11 )
+-c       A = (           ) (           ) = (      ) (R_11 R_12).
+-c           ( Q_21 Q_22 ) (  0    0   )   ( Q_21 )
+-c       Then, the only blocks of the orthogonal factor
+-c       in the above QR decomposition of A that matter are
+-c                                                        ( Q_11 )
+-c       Q_11 and Q_21, _i.e._, only the block of columns (      )
+-c                                                        ( Q_21 )
+-c       interests us.
+-c       Suppose in addition that Q_11 is a k x k matrix,
+-c       Q_21 is an (m-k) x k matrix, and that
+-c       ( Q_11 Q_12 )
+-c       (           ) = _1_ + YTY^T, as in Theorem 1 above.
+-c       ( Q_21 Q_22 )
+-c       Then, Q_11 = _1_ + Y_1 T Y_1^T
+-c       and Q_21 = Y_2 T Y_1^T,
+-c       where Y_1 is the k x k matrix and Y_2 is the (m-k) x k matrix
+-c                   ( Y_1 )
+-c       so that Y = (     ).
+-c                   ( Y_2 )
+-c
+-c       So, you can calculate T and Y via the above recursions,
+-c       and then use these to compute the desired Q_11 and Q_21.
+-c
+-c
+-        implicit none
+-        integer m,n,krank,j,k,mm,ifrescal
+-        real*8 a(m,n),q(m,m),scal
+-c
+-c
+-c       Zero all of the entries of q.
+-c
+-        do k = 1,m
+-          do j = 1,m
+-            q(j,k) = 0
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-c       Place 1's along the diagonal of q.
+-c
+-        do k = 1,m
+-          q(k,k) = 1
+-        enddo ! k
+-c
+-c
+-c       Apply the krank Householder transformations stored in a.
+-c
+-        do k = krank,1,-1
+-          do j = k,m
+-            mm = m-k+1
+-            ifrescal = 1
+-            if(k .lt. m)
+-     1       call idd_houseapp(mm,a(k+1,k),q(k,j),ifrescal,scal,q(k,j))
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_qmatvec(iftranspose,m,n,a,krank,v)
+-c
+-c       applies to a single vector the Q matrix (or its transpose)
+-c       which the routine iddp_qrpiv or iddr_qrpiv has stored
+-c       in a triangle of the matrix it produces (stored, incidentally,
+-c       as data for applying a bunch of Householder reflections).
+-c       Use the routine qmatmat to apply the Q matrix
+-c       (or its transpose)
+-c       to a bunch of vectors collected together as a matrix,
+-c       if you're concerned about efficiency.
+-c
+-c       input:
+-c       iftranspose -- set to 0 for applying Q;
+-c                      set to 1 for applying the transpose of Q
+-c       m -- first dimension of a and length of v
+-c       n -- second dimension of a
+-c       a -- data describing the qr decomposition of a matrix,
+-c            as produced by iddp_qrpiv or iddr_qrpiv
+-c       krank -- numerical rank
+-c       v -- vector to which Q (or its transpose) is to be applied
+-c
+-c       output:
+-c       v -- vector to which Q (or its transpose) has been applied
+-c
+-        implicit none
+-        save
+-        integer m,n,krank,k,ifrescal,mm,iftranspose
+-        real*8 a(m,n),v(m),scal
+-c
+-c
+-        ifrescal = 1
+-c
+-c
+-        if(iftranspose .eq. 0) then
+-c
+-          do k = krank,1,-1
+-            mm = m-k+1
+-            if(k .lt. m)
+-     1       call idd_houseapp(mm,a(k+1,k),v(k),ifrescal,scal,v(k))
+-          enddo ! k
+-c
+-        endif
+-c
+-c
+-        if(iftranspose .eq. 1) then
+-c
+-          do k = 1,krank
+-            mm = m-k+1
+-            if(k .lt. m)
+-     1       call idd_houseapp(mm,a(k+1,k),v(k),ifrescal,scal,v(k))
+-          enddo ! k
+-c
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_qmatmat(iftranspose,m,n,a,krank,l,b,work)
+-c
+-c       applies to a bunch of vectors collected together as a matrix
+-c       the Q matrix (or its transpose) which the routine iddp_qrpiv or
+-c       iddr_qrpiv has stored in a triangle of the matrix it produces
+-c       (stored, incidentally, as data for applying a bunch
+-c       of Householder reflections).
+-c       Use the routine qmatvec to apply the Q matrix
+-c       (or its transpose)
+-c       to a single vector, if you'd rather not provide a work array.
+-c
+-c       input:
+-c       iftranspose -- set to 0 for applying Q;
+-c                      set to 1 for applying the transpose of Q
+-c       m -- first dimension of both a and b
+-c       n -- second dimension of a
+-c       a -- data describing the qr decomposition of a matrix,
+-c            as produced by iddp_qrpiv or iddr_qrpiv
+-c       krank -- numerical rank
+-c       l -- second dimension of b
+-c       b -- matrix to which Q (or its transpose) is to be applied
+-c
+-c       output:
+-c       b -- matrix to which Q (or its transpose) has been applied
+-c
+-c       work:
+-c       work -- must be at least krank real*8 elements long
+-c
+-        implicit none
+-        save
+-        integer l,m,n,krank,j,k,ifrescal,mm,iftranspose
+-        real*8 a(m,n),b(m,l),work(krank)
+-c
+-c
+-        if(iftranspose .eq. 0) then
+-c
+-c
+-c         Handle the first iteration, j = 1,
+-c         calculating all scals (ifrescal = 1).
+-c
+-          ifrescal = 1
+-c
+-          j = 1
+-c
+-          do k = krank,1,-1
+-            if(k .lt. m) then
+-              mm = m-k+1
+-              call idd_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
+-     1                          work(k),b(k,j))
+-            endif
+-          enddo ! k
+-c
+-c
+-          if(l .gt. 1) then
+-c
+-c           Handle the other iterations, j > 1,
+-c           using the scals just computed (ifrescal = 0).
+-c
+-            ifrescal = 0
+-c
+-            do j = 2,l
+-c
+-              do k = krank,1,-1
+-                if(k .lt. m) then
+-                  mm = m-k+1
+-                  call idd_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
+-     1                              work(k),b(k,j))
+-                endif
+-              enddo ! k
+-c
+-            enddo ! j
+-c
+-          endif ! j .gt. 1
+-c
+-c
+-        endif ! iftranspose .eq. 0
+-c
+-c
+-        if(iftranspose .eq. 1) then
+-c
+-c
+-c         Handle the first iteration, j = 1,
+-c         calculating all scals (ifrescal = 1).
+-c
+-          ifrescal = 1
+-c
+-          j = 1
+-c
+-          do k = 1,krank
+-            if(k .lt. m) then
+-              mm = m-k+1
+-              call idd_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
+-     1                          work(k),b(k,j))
+-            endif
+-          enddo ! k
+-c
+-c
+-          if(l .gt. 1) then
+-c
+-c           Handle the other iterations, j > 1,
+-c           using the scals just computed (ifrescal = 0).
+-c
+-            ifrescal = 0
+-c
+-            do j = 2,l
+-c
+-              do k = 1,krank
+-                if(k .lt. m) then
+-                  mm = m-k+1
+-                  call idd_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
+-     1                              work(k),b(k,j))
+-                endif
+-              enddo ! k
+-c
+-            enddo ! j
+-c
+-          endif ! j .gt. 1
+-c
+-c
+-        endif ! iftranspose .eq. 1
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddp_qrpiv(eps,m,n,a,krank,ind,ss)
+-c
+-c       computes the pivoted QR decomposition
+-c       of the matrix input into a, using Householder transformations,
+-c       _i.e._, transforms the matrix a from its input value in
+-c       to the matrix out with entry
+-c
+-c                               m
+-c       out(j,indprod(k))  =  Sigma  q(l,j) * in(l,k),
+-c                              l=1
+-c
+-c       for all j = 1, ..., krank, and k = 1, ..., n,
+-c
+-c       where in = the a from before the routine runs,
+-c       out = the a from after the routine runs,
+-c       out(j,k) = 0 when j > k (so that out is triangular),
+-c       q(1:m,1), ..., q(1:m,krank) are orthonormal,
+-c       indprod is the product of the permutations given by ind,
+-c       (as computable via the routine permmult,
+-c       with the permutation swapping 1 and ind(1) taken leftmost
+-c       in the product, that swapping 2 and ind(2) taken next leftmost,
+-c       ..., that swapping krank and ind(krank) taken rightmost),
+-c       and with the matrix out satisfying
+-c
+-c                   krank
+-c       in(j,k)  =  Sigma  q(j,l) * out(l,indprod(k))  +  epsilon(j,k),
+-c                    l=1
+-c
+-c       for all j = 1, ..., m, and k = 1, ..., n,
+-c
+-c       for some matrix epsilon such that
+-c       the root-sum-square of the entries of epsilon
+-c       <= the root-sum-square of the entries of in * eps.
+-c       Well, technically, this routine outputs the Householder vectors
+-c       (or, rather, their second through last entries)
+-c       in the part of a that is supposed to get zeroed, that is,
+-c       in a(j,k) with m >= j > k >= 1.
+-c
+-c       input:
+-c       eps -- relative precision of the resulting QR decomposition
+-c       m -- first dimension of a and q
+-c       n -- second dimension of a
+-c       a -- matrix whose QR decomposition gets computed
+-c
+-c       output:
+-c       a -- triangular (R) factor in the QR decompositon
+-c            of the matrix input into the same storage locations,
+-c            with the Householder vectors stored in the part of a
+-c            that would otherwise consist entirely of zeroes, that is,
+-c            in a(j,k) with m >= j > k >= 1
+-c       krank -- numerical rank
+-c       ind(k) -- index of the k^th pivot vector;
+-c                 the following code segment will correctly rearrange
+-c                 the product b of q and the upper triangle of out
+-c                 so that b matches the input matrix in
+-c                 to relative precision eps:
+-c
+-c                 copy the non-rearranged product of q and out into b
+-c                 set k to krank
+-c                 [start of loop]
+-c                   swap b(1:m,k) and b(1:m,ind(k))
+-c                   decrement k by 1
+-c                 if k > 0, then go to [start of loop]
+-c
+-c       work:
+-c       ss -- must be at least n real*8 words long
+-c
+-c       _N.B._: This routine outputs the Householder vectors
+-c       (or, rather, their second through last entries)
+-c       in the part of a that is supposed to get zeroed, that is,
+-c       in a(j,k) with m >= j > k >= 1.
+-c
+-c       reference:
+-c       Golub and Van Loan, "Matrix Computations," 3rd edition,
+-c            Johns Hopkins University Press, 1996, Chapter 5.
+-c
+-        implicit none
+-        integer n,m,ind(n),krank,k,j,kpiv,mm,nupdate,ifrescal
+-        real*8 a(m,n),ss(n),eps,feps,ssmax,scal,ssmaxin,rswap
+-c
+-c
+-        feps = .1d-16
+-c
+-c
+-c       Compute the sum of squares of the entries in each column of a,
+-c       the maximum of all such sums, and find the first pivot
+-c       (column with the greatest such sum).
+-c
+-        ssmax = 0
+-        kpiv = 1
+-c
+-        do k = 1,n
+-c
+-          ss(k) = 0
+-          do j = 1,m
+-            ss(k) = ss(k)+a(j,k)**2
+-          enddo ! j
+-c
+-          if(ss(k) .gt. ssmax) then
+-            ssmax = ss(k)
+-            kpiv = k
+-          endif
+-c
+-        enddo ! k
+-c
+-        ssmaxin = ssmax
+-c
+-        nupdate = 0
+-c
+-c
+-c       While ssmax > eps**2*ssmaxin, krank < m, and krank < n,
+-c       do the following block of code,
+-c       which ends at the statement labeled 2000.
+-c
+-        krank = 0
+- 1000   continue
+-c
+-        if(ssmax .le. eps**2*ssmaxin
+-     1   .or. krank .ge. m .or. krank .ge. n) goto 2000
+-        krank = krank+1
+-c
+-c
+-          mm = m-krank+1
+-c
+-c
+-c         Perform the pivoting.
+-c
+-          ind(krank) = kpiv
+-c
+-c         Swap a(1:m,krank) and a(1:m,kpiv).
+-c
+-          do j = 1,m
+-            rswap = a(j,krank)
+-            a(j,krank) = a(j,kpiv)
+-            a(j,kpiv) = rswap
+-          enddo ! j
+-c
+-c         Swap ss(krank) and ss(kpiv).
+-c
+-          rswap = ss(krank)
+-          ss(krank) = ss(kpiv)
+-          ss(kpiv) = rswap
+-c
+-c
+-          if(krank .lt. m) then
+-c
+-c
+-c           Compute the data for the Householder transformation
+-c           which will zero a(krank+1,krank), ..., a(m,krank)
+-c           when applied to a, replacing a(krank,krank)
+-c           with the first entry of the result of the application
+-c           of the Householder matrix to a(krank:m,krank),
+-c           and storing entries 2 to mm of the Householder vector
+-c           in a(krank+1,krank), ..., a(m,krank)
+-c           (which otherwise would get zeroed upon application
+-c           of the Householder transformation).
+-c
+-            call idd_house(mm,a(krank,krank),a(krank,krank),
+-     1                     a(krank+1,krank),scal)
+-            ifrescal = 0
+-c
+-c
+-c           Apply the Householder transformation
+-c           to the lower right submatrix of a
+-c           with upper leftmost entry at position (krank,krank+1).
+-c
+-            if(krank .lt. n) then
+-              do k = krank+1,n
+-                call idd_houseapp(mm,a(krank+1,krank),a(krank,k),
+-     1                            ifrescal,scal,a(krank,k))
+-              enddo ! k
+-            endif
+-c
+-c
+-c           Update the sums-of-squares array ss.
+-c
+-            do k = krank,n
+-              ss(k) = ss(k)-a(krank,k)**2
+-            enddo ! k
+-c
+-c
+-c           Find the pivot (column with the greatest sum of squares
+-c           of its entries).
+-c
+-            ssmax = 0
+-            kpiv = krank+1
+-c
+-            if(krank .lt. n) then
+-c
+-              do k = krank+1,n
+-c
+-                if(ss(k) .gt. ssmax) then
+-                  ssmax = ss(k)
+-                  kpiv = k
+-                endif
+-c
+-              enddo ! k
+-c
+-            endif ! krank .lt. n
+-c
+-c
+-c           Recompute the sums-of-squares and the pivot
+-c           when ssmax first falls below
+-c           sqrt((1000*feps)^2) * ssmaxin
+-c           and when ssmax first falls below
+-c           ((1000*feps)^2) * ssmaxin.
+-c
+-            if(
+-     1       (ssmax .lt. sqrt((1000*feps)**2) * ssmaxin
+-     2        .and. nupdate .eq. 0) .or.
+-     3       (ssmax .lt. ((1000*feps)**2) * ssmaxin
+-     4        .and. nupdate .eq. 1)
+-     5      ) then
+-c
+-              nupdate = nupdate+1
+-c
+-              ssmax = 0
+-              kpiv = krank+1
+-c
+-              if(krank .lt. n) then
+-c
+-                do k = krank+1,n
+-c
+-                  ss(k) = 0
+-                  do j = krank+1,m
+-                    ss(k) = ss(k)+a(j,k)**2
+-                  enddo ! j
+-c
+-                  if(ss(k) .gt. ssmax) then
+-                    ssmax = ss(k)
+-                    kpiv = k
+-                  endif
+-c
+-                enddo ! k
+-c
+-              endif ! krank .lt. n
+-c
+-            endif
+-c
+-c
+-          endif ! krank .lt. m
+-c
+-c
+-        goto 1000
+- 2000   continue
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddr_qrpiv(m,n,a,krank,ind,ss)
+-c
+-c       computes the pivoted QR decomposition
+-c       of the matrix input into a, using Householder transformations,
+-c       _i.e._, transforms the matrix a from its input value in
+-c       to the matrix out with entry
+-c
+-c                               m
+-c       out(j,indprod(k))  =  Sigma  q(l,j) * in(l,k),
+-c                              l=1
+-c
+-c       for all j = 1, ..., krank, and k = 1, ..., n,
+-c
+-c       where in = the a from before the routine runs,
+-c       out = the a from after the routine runs,
+-c       out(j,k) = 0 when j > k (so that out is triangular),
+-c       q(1:m,1), ..., q(1:m,krank) are orthonormal,
+-c       indprod is the product of the permutations given by ind,
+-c       (as computable via the routine permmult,
+-c       with the permutation swapping 1 and ind(1) taken leftmost
+-c       in the product, that swapping 2 and ind(2) taken next leftmost,
+-c       ..., that swapping krank and ind(krank) taken rightmost),
+-c       and with the matrix out satisfying
+-c
+-c                  min(krank,m,n)
+-c       in(j,k)  =     Sigma      q(j,l) * out(l,indprod(k))
+-c                       l=1
+-c
+-c                +  epsilon(j,k),
+-c
+-c       for all j = 1, ..., m, and k = 1, ..., n,
+-c
+-c       for some matrix epsilon whose norm is (hopefully) minimized
+-c       by the pivoting procedure.
+-c       Well, technically, this routine outputs the Householder vectors
+-c       (or, rather, their second through last entries)
+-c       in the part of a that is supposed to get zeroed, that is,
+-c       in a(j,k) with m >= j > k >= 1.
+-c
+-c       input:
+-c       m -- first dimension of a and q
+-c       n -- second dimension of a
+-c       a -- matrix whose QR decomposition gets computed
+-c       krank -- desired rank of the output matrix
+-c                (please note that if krank > m or krank > n,
+-c                then the rank of the output matrix will be
+-c                less than krank)
+-c
+-c       output:
+-c       a -- triangular (R) factor in the QR decompositon
+-c            of the matrix input into the same storage locations,
+-c            with the Householder vectors stored in the part of a
+-c            that would otherwise consist entirely of zeroes, that is,
+-c            in a(j,k) with m >= j > k >= 1
+-c       ind(k) -- index of the k^th pivot vector;
+-c                 the following code segment will correctly rearrange
+-c                 the product b of q and the upper triangle of out
+-c                 so that b best matches the input matrix in:
+-c
+-c                 copy the non-rearranged product of q and out into b
+-c                 set k to krank
+-c                 [start of loop]
+-c                   swap b(1:m,k) and b(1:m,ind(k))
+-c                   decrement k by 1
+-c                 if k > 0, then go to [start of loop]
+-c
+-c       work:
+-c       ss -- must be at least n real*8 words long
+-c
+-c       _N.B._: This routine outputs the Householder vectors
+-c       (or, rather, their second through last entries)
+-c       in the part of a that is supposed to get zeroed, that is,
+-c       in a(j,k) with m >= j > k >= 1.
+-c
+-c       reference:
+-c       Golub and Van Loan, "Matrix Computations," 3rd edition,
+-c            Johns Hopkins University Press, 1996, Chapter 5.
+-c
+-        implicit none
+-        integer n,m,ind(n),krank,k,j,kpiv,mm,nupdate,ifrescal,
+-     1          loops,loop
+-        real*8 a(m,n),ss(n),ssmax,scal,ssmaxin,rswap,feps
+-c
+-c
+-        feps = .1d-16
+-c
+-c
+-c       Compute the sum of squares of the entries in each column of a,
+-c       the maximum of all such sums, and find the first pivot
+-c       (column with the greatest such sum).
+-c
+-        ssmax = 0
+-        kpiv = 1
+-c
+-        do k = 1,n
+-c
+-          ss(k) = 0
+-          do j = 1,m
+-            ss(k) = ss(k)+a(j,k)**2
+-          enddo ! j
+-c
+-          if(ss(k) .gt. ssmax) then
+-            ssmax = ss(k)
+-            kpiv = k
+-          endif
+-c
+-        enddo ! k
+-c
+-        ssmaxin = ssmax
+-c
+-        nupdate = 0
+-c
+-c
+-c       Set loops = min(krank,m,n).
+-c
+-        loops = krank
+-        if(m .lt. loops) loops = m
+-        if(n .lt. loops) loops = n
+-c
+-        do loop = 1,loops
+-c
+-c
+-          mm = m-loop+1
+-c
+-c
+-c         Perform the pivoting.
+-c
+-          ind(loop) = kpiv
+-c
+-c         Swap a(1:m,loop) and a(1:m,kpiv).
+-c
+-          do j = 1,m
+-            rswap = a(j,loop)
+-            a(j,loop) = a(j,kpiv)
+-            a(j,kpiv) = rswap
+-          enddo ! j
+-c
+-c         Swap ss(loop) and ss(kpiv).
+-c
+-          rswap = ss(loop)
+-          ss(loop) = ss(kpiv)
+-          ss(kpiv) = rswap
+-c
+-c
+-          if(loop .lt. m) then
+-c
+-c
+-c           Compute the data for the Householder transformation
+-c           which will zero a(loop+1,loop), ..., a(m,loop)
+-c           when applied to a, replacing a(loop,loop)
+-c           with the first entry of the result of the application
+-c           of the Householder matrix to a(loop:m,loop),
+-c           and storing entries 2 to mm of the Householder vector
+-c           in a(loop+1,loop), ..., a(m,loop)
+-c           (which otherwise would get zeroed upon application
+-c           of the Householder transformation).
+-c
+-            call idd_house(mm,a(loop,loop),a(loop,loop),
+-     1                     a(loop+1,loop),scal)
+-            ifrescal = 0
+-c
+-c
+-c           Apply the Householder transformation
+-c           to the lower right submatrix of a
+-c           with upper leftmost entry at position (loop,loop+1).
+-c
+-            if(loop .lt. n) then
+-              do k = loop+1,n
+-                call idd_houseapp(mm,a(loop+1,loop),a(loop,k),
+-     1                            ifrescal,scal,a(loop,k))
+-              enddo ! k
+-            endif
+-c
+-c
+-c           Update the sums-of-squares array ss.
+-c
+-            do k = loop,n
+-              ss(k) = ss(k)-a(loop,k)**2
+-            enddo ! k
+-c
+-c
+-c           Find the pivot (column with the greatest sum of squares
+-c           of its entries).
+-c
+-            ssmax = 0
+-            kpiv = loop+1
+-c
+-            if(loop .lt. n) then
+-c
+-              do k = loop+1,n
+-c
+-                if(ss(k) .gt. ssmax) then
+-                  ssmax = ss(k)
+-                  kpiv = k
+-                endif
+-c
+-              enddo ! k
+-c
+-            endif ! loop .lt. n
+-c
+-c
+-c           Recompute the sums-of-squares and the pivot
+-c           when ssmax first falls below
+-c           sqrt((1000*feps)^2) * ssmaxin
+-c           and when ssmax first falls below
+-c           ((1000*feps)^2) * ssmaxin.
+-c
+-            if(
+-     1       (ssmax .lt. sqrt((1000*feps)**2) * ssmaxin
+-     2        .and. nupdate .eq. 0) .or.
+-     3       (ssmax .lt. ((1000*feps)**2) * ssmaxin
+-     4        .and. nupdate .eq. 1)
+-     5      ) then
+-c
+-              nupdate = nupdate+1
+-c
+-              ssmax = 0
+-              kpiv = loop+1
+-c
+-              if(loop .lt. n) then
+-c
+-                do k = loop+1,n
+-c
+-                  ss(k) = 0
+-                  do j = loop+1,m
+-                    ss(k) = ss(k)+a(j,k)**2
+-                  enddo ! j
+-c
+-                  if(ss(k) .gt. ssmax) then
+-                    ssmax = ss(k)
+-                    kpiv = k
+-                  endif
+-c
+-                enddo ! k
+-c
+-              endif ! loop .lt. n
+-c
+-            endif
+-c
+-c
+-          endif ! loop .lt. m
+-c
+-c
+-        enddo ! loop
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idd_sfft.f b/scipy/linalg/src/id_dist/src/idd_sfft.f
+deleted file mode 100644
+index e46045ac2..000000000
+--- a/scipy/linalg/src/id_dist/src/idd_sfft.f
++++ /dev/null
+@@ -1,443 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idd_sffti initializes routine idd_sfft.
+-c
+-c       routine idd_sfft rapidly computes a subset of the entries
+-c       of the DFT of a vector, composed with permutation matrices
+-c       both on input and on output.
+-c
+-c       routine idd_ldiv finds the greatest integer less than or equal
+-c       to a specified integer, that is divisible by another (larger)
+-c       specified integer.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idd_ldiv(l,n,m)
+-c
+-c       finds the greatest integer less than or equal to l
+-c       that divides n.
+-c
+-c       input:
+-c       l -- integer at least as great as m
+-c       n -- integer divisible by m
+-c
+-c       output:
+-c       m -- greatest integer less than or equal to l that divides n
+-c
+-        implicit none
+-        integer n,l,m
+-c
+-c
+-        m = l
+-c
+- 1000   continue
+-        if(m*(n/m) .eq. n) goto 2000
+-c
+-          m = m-1
+-          goto 1000
+-c
+- 2000   continue
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_sffti(l,ind,n,wsave)
+-c
+-c       initializes wsave for using routine idd_sfft.
+-c
+-c       input:
+-c       l -- number of pairs of entries in the output of idd_sfft
+-c            to compute
+-c       ind -- indices of the pairs of entries in the output
+-c              of idd_sfft to compute; the indices must be chosen
+-c              in the range from 1 to n/2
+-c       n -- length of the vector to be transformed
+-c
+-c       output:
+-c       wsave -- array needed by routine idd_sfft for processing
+-c                (the present routine does not use the last n elements
+-c                 of wsave, but routine idd_sfft does)
+-c
+-        implicit none
+-        integer l,ind(l),n
+-        complex*16 wsave(2*l+15+4*n)
+-c
+-c
+-        if(l .eq. 1) call idd_sffti1(ind,n,wsave)
+-        if(l .gt. 1) call idd_sffti2(l,ind,n,wsave)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_sffti1(ind,n,wsave)
+-c
+-c       routine idd_sffti serves as a wrapper around
+-c       the present routine; please see routine idd_sffti
+-c       for documentation.
+-c
+-        implicit none
+-        integer ind,n,k
+-        real*8 r1,twopi,wsave(2*(2+15+4*n)),fact
+-c
+-        r1 = 1
+-        twopi = 2*4*atan(r1)
+-c
+-c
+-        fact = 1/sqrt(r1*n)
+-c
+-c
+-        do k = 1,n
+-          wsave(k) = cos(twopi*(k-1)*ind/(r1*n))*fact
+-        enddo ! k
+-c
+-        do k = 1,n
+-          wsave(n+k) = -sin(twopi*(k-1)*ind/(r1*n))*fact
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_sffti2(l,ind,n,wsave)
+-c
+-c       routine idd_sffti serves as a wrapper around
+-c       the present routine; please see routine idd_sffti
+-c       for documentation.
+-c
+-        implicit none
+-        integer l,ind(l),n,nblock,ii,m,idivm,imodm,i,j,k
+-        real*8 r1,twopi,fact
+-        complex*16 wsave(2*l+15+4*n),ci,twopii
+-c
+-        ci = (0,1)
+-        r1 = 1
+-        twopi = 2*4*atan(r1)
+-        twopii = twopi*ci
+-c
+-c
+-c       Determine the block lengths for the FFTs.
+-c
+-        call idd_ldiv(l,n,nblock)
+-        m = n/nblock
+-c
+-c
+-c       Initialize wsave for using routine dfftf.
+-c
+-        call dffti(nblock,wsave)
+-c
+-c
+-c       Calculate the coefficients in the linear combinations
+-c       needed for the direct portion of the calculation.
+-c
+-        fact = 1/sqrt(r1*n)
+-c
+-        ii = 2*l+15
+-c
+-        do j = 1,l
+-c
+-c
+-          i = ind(j)
+-c
+-c
+-          if(i .le. n/2-m/2) then
+-c
+-            idivm = (i-1)/m
+-            imodm = (i-1)-m*idivm
+-c
+-            do k = 1,m
+-              wsave(ii+m*(j-1)+k) = exp(-twopii*(k-1)*imodm/(r1*m))
+-     1         * exp(-twopii*(k-1)*(idivm+1)/(r1*n)) * fact
+-            enddo ! k
+-c
+-          endif ! i .le. n/2-m/2
+-c
+-c
+-          if(i .gt. n/2-m/2) then
+-c
+-            idivm = i/(m/2)
+-            imodm = i-(m/2)*idivm
+-c
+-            do k = 1,m
+-              wsave(ii+m*(j-1)+k) = exp(-twopii*(k-1)*imodm/(r1*m))
+-     1                            * fact
+-            enddo ! k
+-c
+-          endif ! i .gt. n/2-m/2
+-c
+-c
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_sfft(l,ind,n,wsave,v)
+-c
+-c       computes a subset of the entries of the DFT of v,
+-c       composed with permutation matrices both on input and on output,
+-c       via a two-stage procedure (debugging code routine dfftf2 above
+-c       is supposed to calculate the full vector from which idd_sfft
+-c       returns a subset of the entries, when dfftf2 has
+-c       the same parameter nblock as in the present routine).
+-c
+-c       input:
+-c       l -- number of pairs of entries in the output to compute
+-c       ind -- indices of the pairs of entries in the output
+-c              to compute; the indices must be chosen
+-c              in the range from 1 to n/2
+-c       n -- length of v; n must be a positive integer power of 2
+-c       v -- vector to be transformed
+-c       wsave -- processing array initialized by routine idd_sffti
+-c
+-c       output:
+-c       v -- pairs of entries indexed by ind are given
+-c            their appropriately transformed values
+-c
+-c       _N.B._: n must be a positive integer power of 2.
+-c
+-c       references:
+-c       Sorensen and Burrus, "Efficient computation of the DFT with
+-c            only a subset of input or output points,"
+-c            IEEE Transactions on Signal Processing, 41 (3): 1184-1200,
+-c            1993.
+-c       Woolfe, Liberty, Rokhlin, Tygert, "A fast randomized algorithm
+-c            for the approximation of matrices," Applied and
+-c            Computational Harmonic Analysis, 25 (3): 335-366, 2008;
+-c            Section 3.3.
+-c
+-        implicit none
+-        integer l,ind(l),n
+-        real*8 v(n)
+-        complex*16 wsave(2*l+15+4*n)
+-c
+-c
+-        if(l .eq. 1) call idd_sfft1(ind,n,v,wsave)
+-        if(l .gt. 1) call idd_sfft2(l,ind,n,v,wsave)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_sfft1(ind,n,v,wsave)
+-c
+-c       routine idd_sfft serves as a wrapper around
+-c       the present routine; please see routine idd_sfft
+-c       for documentation.
+-c
+-        implicit none
+-        integer ind,n,k
+-        real*8 v(n),r1,twopi,sumr,sumi,fact,wsave(2*(2+15+4*n))
+-c
+-        r1 = 1
+-        twopi = 2*4*atan(r1)
+-c
+-c
+-        if(ind .lt. n/2) then
+-c
+-c
+-          sumr = 0
+-c
+-          do k = 1,n
+-            sumr = sumr+wsave(k)*v(k)
+-          enddo ! k
+-c
+-c
+-          sumi = 0
+-c
+-          do k = 1,n
+-            sumi = sumi+wsave(n+k)*v(k)
+-          enddo ! k
+-c
+-c
+-        endif ! ind .lt. n/2
+-c
+-c
+-        if(ind .eq. n/2) then
+-c
+-c
+-          fact = 1/sqrt(r1*n)
+-c
+-c
+-          sumr = 0
+-c
+-          do k = 1,n
+-            sumr = sumr+v(k)
+-          enddo ! k
+-c
+-          sumr = sumr*fact
+-c
+-c
+-          sumi = 0
+-c
+-          do k = 1,n/2
+-            sumi = sumi+v(2*k-1)
+-            sumi = sumi-v(2*k)
+-          enddo ! k
+-c
+-          sumi = sumi*fact
+-c
+-c
+-        endif ! ind .eq. n/2
+-c
+-c
+-        v(2*ind-1) = sumr
+-        v(2*ind) = sumi
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_sfft2(l,ind,n,v,wsave)
+-c
+-c       routine idd_sfft serves as a wrapper around
+-c       the present routine; please see routine idd_sfft
+-c       for documentation.
+-c
+-        implicit none
+-        integer n,m,l,k,j,ind(l),i,idivm,nblock,ii,iii,imodm
+-        real*8 r1,twopi,v(n),rsum,fact
+-        complex*16 wsave(2*l+15+4*n),ci,sum
+-c
+-        ci = (0,1)
+-        r1 = 1
+-        twopi = 2*4*atan(r1)
+-c
+-c
+-c       Determine the block lengths for the FFTs.
+-c
+-        call idd_ldiv(l,n,nblock)
+-c
+-c
+-        m = n/nblock
+-c
+-c
+-c       FFT each block of length nblock of v.
+-c
+-        do k = 1,m
+-          call dfftf(nblock,v(nblock*(k-1)+1),wsave)
+-        enddo ! k
+-c
+-c
+-c       Transpose v to obtain wsave(2*l+15+2*n+1 : 2*l+15+3*n).
+-c
+-        iii = 2*l+15+2*n
+-c
+-        do k = 1,m
+-          do j = 1,nblock/2-1
+-            wsave(iii+m*(j-1)+k) = v(nblock*(k-1)+2*j)
+-     1                           + ci*v(nblock*(k-1)+2*j+1)
+-          enddo ! j
+-        enddo ! k
+-c
+-c       Handle the purely real frequency components separately.
+-c
+-        do k = 1,m
+-          wsave(iii+m*(nblock/2-1)+k) = v(nblock*(k-1)+nblock)
+-          wsave(iii+m*(nblock/2)+k) = v(nblock*(k-1)+1)
+-        enddo ! k
+-c
+-c
+-c       Directly calculate the desired entries of v.
+-c
+-        ii = 2*l+15
+-c
+-        do j = 1,l
+-c
+-c
+-          i = ind(j)
+-c
+-c
+-          if(i .le. n/2-m/2) then
+-c
+-            idivm = (i-1)/m
+-            imodm = (i-1)-m*idivm
+-c
+-            sum = 0
+-c
+-            do k = 1,m
+-              sum = sum + wsave(iii+m*idivm+k) * wsave(ii+m*(j-1)+k)
+-            enddo ! k
+-c
+-            v(2*i-1) = sum
+-            v(2*i) = -ci*sum
+-c
+-          endif ! i .le. n/2-m/2
+-c
+-c
+-          if(i .gt. n/2-m/2) then
+-c
+-            if(i .lt. n/2) then
+-c
+-              idivm = i/(m/2)
+-              imodm = i-(m/2)*idivm
+-c
+-              sum = 0
+-c
+-              do k = 1,m
+-                sum = sum + wsave(iii+m*(nblock/2)+k)
+-     1              * wsave(ii+m*(j-1)+k)
+-              enddo ! k
+-c
+-              v(2*i-1) = sum
+-              v(2*i) = -ci*sum
+-c
+-            endif
+-c
+-            if(i .eq. n/2) then
+-c
+-              fact = 1/sqrt(r1*n)
+-c
+-c
+-              rsum = 0
+-c
+-              do k = 1,m
+-                rsum = rsum + wsave(iii+m*(nblock/2)+k)
+-              enddo ! k
+-c
+-              v(n-1) = rsum*fact
+-c
+-c
+-              rsum = 0
+-c
+-              do k = 1,m/2
+-                rsum = rsum + wsave(iii+m*(nblock/2)+2*k-1)
+-                rsum = rsum - wsave(iii+m*(nblock/2)+2*k)
+-              enddo ! k
+-c
+-              v(n) = rsum*fact
+-c
+-            endif
+-c
+-          endif ! i .gt. n/2-m/2
+-c
+-c
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idd_snorm.f b/scipy/linalg/src/id_dist/src/idd_snorm.f
+deleted file mode 100644
+index c718ce12f..000000000
+--- a/scipy/linalg/src/id_dist/src/idd_snorm.f
++++ /dev/null
+@@ -1,400 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idd_snorm estimates the spectral norm
+-c       of a matrix specified by routines for applying the matrix
+-c       and its transpose to arbitrary vectors. This routine uses
+-c       the power method with a random starting vector.
+-c
+-c       routine idd_diffsnorm estimates the spectral norm
+-c       of the difference between two matrices specified by routines
+-c       for applying the matrices and their transposes
+-c       to arbitrary vectors. This routine uses
+-c       the power method with a random starting vector.
+-c
+-c       routine idd_enorm calculates the Euclidean norm of a vector.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idd_snorm(m,n,matvect,p1t,p2t,p3t,p4t,
+-     1                       matvec,p1,p2,p3,p4,its,snorm,v,u)
+-c
+-c       estimates the spectral norm of a matrix a specified
+-c       by a routine matvec for applying a to an arbitrary vector,
+-c       and by a routine matvect for applying a^T
+-c       to an arbitrary vector. This routine uses the power method
+-c       with a random starting vector.
+-c
+-c       input:
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       matvect -- routine which applies the transpose of a
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matvect(m,x,n,y,p1t,p2t,p3t,p4t),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the transpose of a
+-c                  is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the transpose of a and x,
+-c                  and p1t, p2t, p3t, and p4t are user-specified
+-c                  parameters
+-c       p1t -- parameter to be passed to routine matvect
+-c       p2t -- parameter to be passed to routine matvect
+-c       p3t -- parameter to be passed to routine matvect
+-c       p4t -- parameter to be passed to routine matvect
+-c       matvec -- routine which applies the matrix a
+-c                 to an arbitrary vector; this routine must have
+-c                 a calling sequence of the form
+-c
+-c                 matvec(n,x,m,y,p1,p2,p3,p4),
+-c
+-c                 where n is the length of x,
+-c                 x is the vector to which a is to be applied,
+-c                 m is the length of y,
+-c                 y is the product of a and x,
+-c                 and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvec
+-c       p2 -- parameter to be passed to routine matvec
+-c       p3 -- parameter to be passed to routine matvec
+-c       p4 -- parameter to be passed to routine matvec
+-c       its -- number of iterations of the power method to conduct
+-c
+-c       output:
+-c       snorm -- estimate of the spectral norm of a
+-c       v -- estimate of a normalized right singular vector
+-c            corresponding to the greatest singular value of a
+-c
+-c       work:
+-c       u -- must be at least m real*8 elements long
+-c
+-c       reference:
+-c       Kuczynski and Wozniakowski, "Estimating the largest eigenvalue
+-c            by the power and Lanczos algorithms with a random start,"
+-c            SIAM Journal on Matrix Analysis and Applications,
+-c            13 (4): 1992, 1094-1122.
+-c
+-        implicit none
+-        integer m,n,its,it,k
+-        real*8 snorm,enorm,p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m),v(n)
+-        external matvect,matvec
+-c
+-c
+-c       Fill the real and imaginary parts of each entry
+-c       of the initial vector v with i.i.d. random variables
+-c       drawn uniformly from [-1,1].
+-c
+-        call id_srand(n,v)
+-c
+-        do k = 1,n
+-          v(k) = 2*v(k)-1
+-        enddo ! k
+-c
+-c
+-c       Normalize v.
+-c
+-        call idd_enorm(n,v,enorm)
+-c
+-        do k = 1,n
+-          v(k) = v(k)/enorm
+-        enddo ! k
+-c
+-c
+-        do it = 1,its
+-c
+-c         Apply a to v, obtaining u.
+-c
+-          call matvec(n,v,m,u,p1,p2,p3,p4)
+-c
+-c         Apply a^T to u, obtaining v.
+-c
+-          call matvect(m,u,n,v,p1t,p2t,p3t,p4t)
+-c
+-c         Normalize v.
+-c
+-          call idd_enorm(n,v,snorm)
+-c
+-          if(snorm .gt. 0) then
+-c
+-            do k = 1,n
+-              v(k) = v(k)/snorm
+-            enddo ! k
+-c
+-          endif
+-c
+-          snorm = sqrt(snorm)
+-c
+-        enddo ! it
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_enorm(n,v,enorm)
+-c
+-c       computes the Euclidean norm of v, the square root
+-c       of the sum of the squares of the entries of v.
+-c
+-c       input:
+-c       n -- length of v
+-c       v -- vector whose Euclidean norm is to be calculated
+-c
+-c       output:
+-c       enorm -- Euclidean norm of v
+-c
+-        implicit none
+-        integer n,k
+-        real*8 enorm,v(n)
+-c
+-c
+-        enorm = 0
+-c
+-        do k = 1,n
+-          enorm = enorm+v(k)**2
+-        enddo ! k
+-c
+-        enorm = sqrt(enorm)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_diffsnorm(m,n,matvect,p1t,p2t,p3t,p4t,
+-     1                           matvect2,p1t2,p2t2,p3t2,p4t2,
+-     2                           matvec,p1,p2,p3,p4,
+-     3                           matvec2,p12,p22,p32,p42,its,snorm,w)
+-c
+-c       estimates the spectral norm of the difference between matrices
+-c       a and a2, where a is specified by routines matvec and matvect
+-c       for applying a and a^T to arbitrary vectors,
+-c       and a2 is specified by routines matvec2 and matvect2
+-c       for applying a2 and (a2)^T to arbitrary vectors.
+-c       This routine uses the power method
+-c       with a random starting vector.
+-c
+-c       input:
+-c       m -- number of rows in a, as well as the number of rows in a2
+-c       n -- number of columns in a, as well as the number of columns
+-c            in a2
+-c       matvect -- routine which applies the transpose of a
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matvect(m,x,n,y,p1t,p2t,p3t,p4t),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the transpose of a
+-c                  is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the transpose of a and x,
+-c                  and p1t, p2t, p3t, and p4t are user-specified
+-c                  parameters
+-c       p1t -- parameter to be passed to routine matvect
+-c       p2t -- parameter to be passed to routine matvect
+-c       p3t -- parameter to be passed to routine matvect
+-c       p4t -- parameter to be passed to routine matvect
+-c       matvect2 -- routine which applies the transpose of a2
+-c                   to an arbitrary vector; this routine must have
+-c                   a calling sequence of the form
+-c
+-c                   matvect2(m,x,n,y,p1t2,p2t2,p3t2,p4t2),
+-c
+-c                   where m is the length of x,
+-c                   x is the vector to which the transpose of a2
+-c                   is to be applied,
+-c                   n is the length of y,
+-c                   y is the product of the transpose of a2 and x,
+-c                   and p1t2, p2t2, p3t2, and p4t2 are user-specified
+-c                   parameters
+-c       p1t2 -- parameter to be passed to routine matvect2
+-c       p2t2 -- parameter to be passed to routine matvect2
+-c       p3t2 -- parameter to be passed to routine matvect2
+-c       p4t2 -- parameter to be passed to routine matvect2
+-c       matvec -- routine which applies the matrix a
+-c                 to an arbitrary vector; this routine must have
+-c                 a calling sequence of the form
+-c
+-c                 matvec(n,x,m,y,p1,p2,p3,p4),
+-c
+-c                 where n is the length of x,
+-c                 x is the vector to which a is to be applied,
+-c                 m is the length of y,
+-c                 y is the product of a and x,
+-c                 and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvec
+-c       p2 -- parameter to be passed to routine matvec
+-c       p3 -- parameter to be passed to routine matvec
+-c       p4 -- parameter to be passed to routine matvec
+-c       matvec2 -- routine which applies the matrix a2
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matvec2(n,x,m,y,p12,p22,p32,p42),
+-c
+-c                  where n is the length of x,
+-c                  x is the vector to which a2 is to be applied,
+-c                  m is the length of y,
+-c                  y is the product of a2 and x, and
+-c                  p12, p22, p32, and p42 are user-specified parameters
+-c       p12 -- parameter to be passed to routine matvec2
+-c       p22 -- parameter to be passed to routine matvec2
+-c       p32 -- parameter to be passed to routine matvec2
+-c       p42 -- parameter to be passed to routine matvec2
+-c       its -- number of iterations of the power method to conduct
+-c
+-c       output:
+-c       snorm -- estimate of the spectral norm of a-a2
+-c
+-c       work:
+-c       w -- must be at least 3*m+3*n real*8 elements long
+-c
+-c       reference:
+-c       Kuczynski and Wozniakowski, "Estimating the largest eigenvalue
+-c            by the power and Lanczos algorithms with a random start,"
+-c            SIAM Journal on Matrix Analysis and Applications,
+-c            13 (4): 1992, 1094-1122.
+-c
+-        implicit none
+-        integer m,n,its,lw,iu,lu,iu1,lu1,iu2,lu2,
+-     1          iv,lv,iv1,lv1,iv2,lv2
+-        real*8 snorm,p1t,p2t,p3t,p4t,p1t2,p2t2,p3t2,p4t2,
+-     1         p1,p2,p3,p4,p12,p22,p32,p42,w(3*m+3*n)
+-        external matvect,matvec,matvect2,matvec2
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw = 0
+-c
+-        iu = lw+1
+-        lu = m
+-        lw = lw+lu
+-c
+-        iu1 = lw+1
+-        lu1 = m
+-        lw = lw+lu1
+-c
+-        iu2 = lw+1
+-        lu2 = m
+-        lw = lw+lu2
+-c
+-        iv = lw+1
+-        lv = n
+-        lw = lw+1
+-c
+-        iv1 = lw+1
+-        lv1 = n
+-        lw = lw+lv1
+-c
+-        iv2 = lw+1
+-        lv2 = n
+-        lw = lw+lv2
+-c
+-c
+-        call idd_diffsnorm0(m,n,matvect,p1t,p2t,p3t,p4t,
+-     1                      matvect2,p1t2,p2t2,p3t2,p4t2,
+-     2                      matvec,p1,p2,p3,p4,
+-     3                      matvec2,p12,p22,p32,p42,
+-     4                      its,snorm,w(iu),w(iu1),w(iu2),
+-     5                      w(iv),w(iv1),w(iv2))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_diffsnorm0(m,n,matvect,p1t,p2t,p3t,p4t,
+-     1                            matvect2,p1t2,p2t2,p3t2,p4t2,
+-     2                            matvec,p1,p2,p3,p4,
+-     3                            matvec2,p12,p22,p32,p42,
+-     4                            its,snorm,u,u1,u2,v,v1,v2)
+-c
+-c       routine idd_diffsnorm serves as a memory wrapper
+-c       for the present routine. (Please see routine idd_diffsnorm
+-c       for further documentation.)
+-c
+-        implicit none
+-        integer m,n,its,it,k
+-        real*8 snorm,enorm,p1t,p2t,p3t,p4t,p1t2,p2t2,p3t2,p4t2,
+-     1         p1,p2,p3,p4,p12,p22,p32,p42,u(m),u1(m),u2(m),
+-     2         v(n),v1(n),v2(n)
+-        external matvect,matvec,matvect2,matvec2
+-c
+-c
+-c       Fill the real and imaginary parts of each entry
+-c       of the initial vector v with i.i.d. random variables
+-c       drawn uniformly from [-1,1].
+-c
+-        call id_srand(n,v)
+-c
+-        do k = 1,n
+-          v(k) = 2*v(k)-1
+-        enddo ! k
+-c
+-c
+-c       Normalize v.
+-c
+-        call idd_enorm(n,v,enorm)
+-c
+-        do k = 1,n
+-          v(k) = v(k)/enorm
+-        enddo ! k
+-c
+-c
+-        do it = 1,its
+-c
+-c         Apply a and a2 to v, obtaining u1 and u2.
+-c
+-          call matvec(n,v,m,u1,p1,p2,p3,p4)
+-          call matvec2(n,v,m,u2,p12,p22,p32,p42)
+-c
+-c         Form u = u1-u2.
+-c
+-          do k = 1,m
+-            u(k) = u1(k)-u2(k)
+-          enddo ! k
+-c
+-c         Apply a^T and (a2)^T to u, obtaining v1 and v2.
+-c
+-          call matvect(m,u,n,v1,p1t,p2t,p3t,p4t)
+-          call matvect2(m,u,n,v2,p1t2,p2t2,p3t2,p4t2)
+-c
+-c         Form v = v1-v2.
+-c
+-          do k = 1,n
+-            v(k) = v1(k)-v2(k)
+-          enddo ! k
+-c
+-c         Normalize v.
+-c
+-          call idd_enorm(n,v,snorm)
+-c
+-          if(snorm .gt. 0) then
+-c
+-            do k = 1,n
+-              v(k) = v(k)/snorm
+-            enddo ! k
+-c
+-          endif
+-c
+-          snorm = sqrt(snorm)
+-c
+-        enddo ! it
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idd_svd.f b/scipy/linalg/src/id_dist/src/idd_svd.f
+deleted file mode 100644
+index 969422b8c..000000000
+--- a/scipy/linalg/src/id_dist/src/idd_svd.f
++++ /dev/null
+@@ -1,409 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddr_svd computes an approximation of specified rank
+-c       to a given matrix, in the usual SVD form U S V^T,
+-c       where U has orthonormal columns, V has orthonormal columns,
+-c       and S is diagonal.
+-c
+-c       routine iddp_svd computes an approximation of specified
+-c       precision to a given matrix, in the usual SVD form U S V^T,
+-c       where U has orthonormal columns, V has orthonormal columns,
+-c       and S is diagonal.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine iddr_svd(m,n,a,krank,u,v,s,ier,r)
+-c
+-c       constructs a rank-krank SVD  u diag(s) v^T  approximating a,
+-c       where u is an m x krank matrix whose columns are orthonormal,
+-c       v is an n x krank matrix whose columns are orthonormal,
+-c       and diag(s) is a diagonal krank x krank matrix whose entries
+-c       are all nonnegative. This routine combines a QR code
+-c       (which is based on plane/Householder reflections)
+-c       with the LAPACK routine dgesdd.
+-c
+-c       input:
+-c       m -- first dimension of a and u
+-c       n -- second dimension of a, and first dimension of v
+-c       a -- matrix to be SVD'd
+-c       krank -- desired rank of the approximation to a
+-c
+-c       output:
+-c       u -- left singular vectors of a corresponding
+-c            to the k greatest singular values of a
+-c       v -- right singular vectors of a corresponding
+-c            to the k greatest singular values of a
+-c       s -- k greatest singular values of a
+-c       ier -- 0 when the routine terminates successfully;
+-c              nonzero when the routine encounters an error
+-c
+-c       work:
+-c       r -- must be at least
+-c            (krank+2)*n+8*min(m,n)+15*krank**2+8*krank
+-c            real*8 elements long
+-c
+-c       _N.B._: This routine destroys a. Also, please beware that
+-c               the source code for this routine could be clearer.
+-c
+-        implicit none
+-        character*1 jobz
+-        integer m,n,k,krank,iftranspose,ldr,ldu,ldvt,lwork,
+-     1          info,j,ier,io
+-        real*8 a(m,n),u(m,krank),v(n*krank),s(krank),r(*)
+-c
+-c
+-        io = 8*min(m,n)
+-c
+-c
+-        ier = 0
+-c
+-c
+-c       Compute a pivoted QR decomposition of a.
+-c
+-        call iddr_qrpiv(m,n,a,krank,r,r(io+1))
+-c
+-c
+-c       Extract R from the QR decomposition.
+-c
+-        call idd_retriever(m,n,a,krank,r(io+1))
+-c
+-c
+-c       Rearrange R according to ind (which is stored in r).
+-c
+-        call idd_permuter(krank,r,krank,n,r(io+1))
+-c
+-c
+-c       Use LAPACK to SVD R,
+-c       storing the krank (krank x 1) left singular vectors
+-c       in r(io+krank*n+1 : io+krank*n+krank*krank).
+-c
+-        jobz = 'S'
+-        ldr = krank
+-        lwork = 2*(3*krank**2+n+4*krank**2+4*krank)
+-        ldu = krank
+-        ldvt = krank
+-c
+-        call dgesdd(jobz,krank,n,r(io+1),ldr,s,r(io+krank*n+1),ldu,
+-     1              v,ldvt,r(io+krank*n+krank*krank+1),lwork,r,info)
+-c
+-        if(info .ne. 0) then
+-          ier = info
+-          return
+-        endif
+-c
+-c
+-c       Multiply the U from R from the left by Q to obtain the U
+-c       for A.
+-c
+-        do k = 1,krank
+-c
+-          do j = 1,krank
+-            u(j,k) = r(io+krank*n+j+krank*(k-1))
+-          enddo ! j
+-c
+-          do j = krank+1,m
+-            u(j,k) = 0
+-          enddo ! j
+-c
+-        enddo ! k
+-c
+-        iftranspose = 0
+-        call idd_qmatmat(iftranspose,m,n,a,krank,krank,u,r)
+-c
+-c
+-c       Transpose v to obtain r.
+-c
+-        call idd_transer(krank,n,v,r)
+-c
+-c
+-c       Copy r into v.
+-c
+-        do k = 1,n*krank
+-          v(k) = r(k)
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddp_svd(lw,eps,m,n,a,krank,iu,iv,is,w,ier)
+-c
+-c       constructs a rank-krank SVD  U Sigma V^T  approximating a
+-c       to precision eps, where U is an m x krank matrix whose
+-c       columns are orthonormal, V is an n x krank matrix whose
+-c       columns are orthonormal, and Sigma is a diagonal krank x krank
+-c       matrix whose entries are all nonnegative.
+-c       The entries of U are stored in w, starting at w(iu);
+-c       the entries of V are stored in w, starting at w(iv).
+-c       The diagonal entries of Sigma are stored in w,
+-c       starting at w(is). This routine combines a QR code
+-c       (which is based on plane/Householder reflections)
+-c       with the LAPACK routine dgesdd.
+-c
+-c       input:
+-c       lw -- maximum usable length of w (in real*8 elements)
+-c       eps -- precision to which the SVD approximates a
+-c       m -- first dimension of a and u
+-c       n -- second dimension of a, and first dimension of v
+-c       a -- matrix to be SVD'd
+-c
+-c       output:
+-c       krank -- rank of the approximation to a
+-c       iu -- index in w of the first entry of the matrix
+-c             of orthonormal left singular vectors of a
+-c       iv -- index in w of the first entry of the matrix
+-c             of orthonormal right singular vectors of a
+-c       is -- index in w of the first entry of the array
+-c             of singular values of a
+-c       w -- array containing the singular values and singular vectors
+-c            of a; w doubles as a work array, and so must be at least
+-c            (krank+1)*(m+2*n+9)+8*min(m,n)+15*krank**2
+-c            real*8 elements long, where krank is the rank
+-c            output by the present routine
+-c       ier -- 0 when the routine terminates successfully;
+-c              -1000 when lw is too small;
+-c              other nonzero values when dgesdd bombs
+-c
+-c       _N.B._: This routine destroys a. Also, please beware that
+-c               the source code for this routine could be clearer.
+-c               w must be at least
+-c               (krank+1)*(m+2*n+9)+8*min(m,n)+15*krank**2
+-c               real*8 elements long, where krank is the rank
+-c               output by the present routine.
+-c
+-        implicit none
+-        character*1 jobz
+-        integer m,n,k,krank,iftranspose,ldr,ldu,ldvt,lwork,
+-     1          info,j,ier,io,iu,iv,is,ivi,isi,lw,lu,lv,ls
+-        real*8 a(m,n),w(*),eps
+-c
+-c
+-        io = 8*min(m,n)
+-c
+-c
+-        ier = 0
+-c
+-c
+-c       Compute a pivoted QR decomposition of a.
+-c
+-        call iddp_qrpiv(eps,m,n,a,krank,w,w(io+1))
+-c
+-c
+-        if(krank .gt. 0) then
+-c
+-c
+-c         Extract R from the QR decomposition.
+-c
+-          call idd_retriever(m,n,a,krank,w(io+1))
+-c
+-c
+-c         Rearrange R according to ind (which is stored in w).
+-c
+-          call idd_permuter(krank,w,krank,n,w(io+1))
+-c
+-c
+-c         Use LAPACK to SVD R,
+-c         storing the krank (krank x 1) left singular vectors
+-c         in w(io+krank*n+1 : io+krank*n+krank*krank).
+-c
+-          jobz = 'S'
+-          ldr = krank
+-          lwork = 2*(3*krank**2+n+4*krank**2+4*krank)
+-          ldu = krank
+-          ldvt = krank
+-c
+-          ivi = io+krank*n+krank*krank+lwork+1
+-          lv = n*krank
+-c
+-          isi = ivi+lv
+-          ls = krank
+-c
+-          if(lw .lt. isi+ls+m*krank-1) then
+-            ier = -1000
+-            return
+-          endif
+-c
+-          call dgesdd(jobz,krank,n,w(io+1),ldr,w(isi),w(io+krank*n+1),
+-     1                ldu,w(ivi),ldvt,w(io+krank*n+krank*krank+1),
+-     2                lwork,w,info)
+-c
+-          if(info .ne. 0) then
+-            ier = info
+-            return
+-          endif
+-c
+-c
+-c         Transpose w(ivi:ivi+lv-1) to obtain V.
+-c
+-          iv = 1
+-          call idd_transer(krank,n,w(ivi),w(iv))
+-c
+-c
+-c         Copy w(isi:isi+ls-1) into w(is:is+ls-1).
+-c
+-          is = iv+lv
+-c
+-          do k = 1,ls
+-            w(is+k-1) = w(isi+k-1)
+-          enddo ! k
+-c
+-c
+-c         Multiply the U from R from the left by Q to obtain the U
+-c         for A.
+-c
+-          iu = is+ls
+-          lu = m*krank
+-c
+-          do k = 1,krank
+-c
+-            do j = 1,krank
+-              w(iu-1+j+krank*(k-1)) = w(io+krank*n+j+krank*(k-1))
+-            enddo ! j
+-c
+-          enddo ! k
+-c
+-          do k = krank,1,-1
+-c
+-            do j = m,krank+1,-1
+-              w(iu-1+j+m*(k-1)) = 0
+-            enddo ! j
+-c
+-            do j = krank,1,-1
+-              w(iu-1+j+m*(k-1)) = w(iu-1+j+krank*(k-1))
+-            enddo ! j
+-c
+-          enddo ! k
+-c
+-          iftranspose = 0
+-          call idd_qmatmat(iftranspose,m,n,a,krank,krank,w(iu),
+-     1                     w(iu+lu+1))
+-c
+-c
+-        endif ! krank .gt. 0
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_permuter(krank,ind,m,n,a)
+-c
+-c       permutes the columns of a according to ind obtained
+-c       from routine iddr_qrpiv or iddp_qrpiv, assuming that
+-c       a = q r from iddr_qrpiv or iddp_qrpiv.
+-c
+-c       input:
+-c       krank -- rank specified to routine iddr_qrpiv
+-c                or obtained from routine iddp_qrpiv
+-c       ind -- indexing array obtained from routine iddr_qrpiv
+-c              or iddp_qrpiv
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       a -- matrix to be rearranged
+-c
+-c       output:
+-c       a -- rearranged matrix
+-c
+-        implicit none
+-        integer k,krank,m,n,j,ind(krank)
+-        real*8 rswap,a(m,n)
+-c
+-c
+-        do k = krank,1,-1
+-          do j = 1,m
+-c
+-            rswap = a(j,k)
+-            a(j,k) = a(j,ind(k))
+-            a(j,ind(k)) = rswap
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_retriever(m,n,a,krank,r)
+-c
+-c       extracts R in the QR decomposition specified by the output a
+-c       of the routine iddr_qrpiv or iddp_qrpiv
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a and r
+-c       a -- output of routine iddr_qrpiv or iddp_qrpiv
+-c       krank -- rank specified to routine iddr_qrpiv,
+-c                or output by routine iddp_qrpiv
+-c
+-c       output:
+-c       r -- triangular factor in the QR decomposition specified
+-c            by the output a of the routine iddr_qrpiv or iddp_qrpiv
+-c
+-        implicit none
+-        integer m,n,j,k,krank
+-        real*8 a(m,n),r(krank,n)
+-c
+-c
+-c       Copy a into r and zero out the appropriate
+-c       Householder vectors that are stored in one triangle of a.
+-c
+-        do k = 1,n
+-          do j = 1,krank
+-            r(j,k) = a(j,k)
+-          enddo ! j
+-        enddo ! k
+-c
+-        do k = 1,n
+-          if(k .lt. krank) then
+-            do j = k+1,krank
+-              r(j,k) = 0
+-            enddo ! j
+-          endif
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_transer(m,n,a,at)
+-c
+-c       forms the transpose at of a.
+-c
+-c       input:
+-c       m -- first dimension of a and second dimension of at
+-c       n -- second dimension of a and first dimension of at
+-c       a -- matrix to be transposed
+-c
+-c       output:
+-c       at -- transpose of a
+-c
+-        implicit none
+-        integer m,n,j,k
+-        real*8 a(m,n),at(n,m)
+-c
+-c
+-        do k = 1,n
+-          do j = 1,m
+-            at(k,j) = a(j,k)
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/iddp_aid.f b/scipy/linalg/src/id_dist/src/iddp_aid.f
+deleted file mode 100644
+index f3f9ddfdd..000000000
+--- a/scipy/linalg/src/id_dist/src/iddp_aid.f
++++ /dev/null
+@@ -1,386 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddp_aid computes the ID, to a specified precision,
+-c       of an arbitrary matrix. This routine is randomized.
+-c
+-c       routine idd_estrank estimates the numerical rank,
+-c       to a specified precision, of an arbitrary matrix.
+-c       This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine iddp_aid(eps,m,n,a,work,krank,list,proj)
+-c
+-c       computes the ID of the matrix a, i.e., lists in list
+-c       the indices of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                        krank
+-c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
+-c                         l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon dimensioned epsilon(m,n-krank)
+-c       such that the greatest singular value of epsilon
+-c       <= the greatest singular value of a * eps.
+-c
+-c       input:
+-c       eps -- precision to which the ID is to be computed
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       a -- matrix to be decomposed; the present routine does not
+-c            alter a
+-c       work -- initialization array that has been constructed
+-c               by routine idd_frmi
+-c
+-c       output:
+-c       krank -- numerical rank of a to precision eps
+-c       list -- indices of the columns in the ID
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns
+-c               in the original matrix being ID'd;
+-c               proj doubles as a work array in the present routine, so
+-c               proj must be at least n*(2*n2+1)+n2+1 real*8 elements
+-c               long, where n2 is the greatest integer less than
+-c               or equal to m, such that n2 is a positive integer
+-c               power of two.
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c               proj must be at least n*(2*n2+1)+n2+1 real*8 elements
+-c               long, where n2 is the greatest integer less than
+-c               or equal to m, such that n2 is a positive integer
+-c               power of two.
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,n,list(n),krank,kranki,n2
+-        real*8 eps,a(m,n),proj(*),work(17*m+70)
+-c
+-c
+-c       Allocate memory in proj.
+-c
+-        n2 = work(2)
+-c
+-c
+-c       Find the rank of a.
+-c
+-        call idd_estrank(eps,m,n,a,work,kranki,proj)
+-c
+-c
+-        if(kranki .eq. 0) call iddp_aid0(eps,m,n,a,krank,list,proj,
+-     1                                   proj(m*n+1))
+-c
+-        if(kranki .ne. 0) call iddp_aid1(eps,n2,n,kranki,proj,
+-     1                                   krank,list,proj(n2*n+1))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddp_aid0(eps,m,n,a,krank,list,proj,rnorms)
+-c
+-c       uses routine iddp_id to ID a without modifying its entries
+-c       (in contrast to the usual behavior of iddp_id).
+-c
+-c       input:
+-c       eps -- precision of the decomposition to be constructed
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c
+-c       output:
+-c       krank -- numerical rank of the ID
+-c       list -- indices of the columns in the ID
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns in a;
+-c               proj doubles as a work array in the present routine, so
+-c               must be at least m*n real*8 elements long
+-c
+-c       work:
+-c       rnorms -- must be at least n real*8 elements long
+-c
+-c       _N.B._: proj must be at least m*n real*8 elements long
+-c
+-        implicit none
+-        integer m,n,krank,list(n),j,k
+-        real*8 eps,a(m,n),proj(m,n),rnorms(n)
+-c
+-c
+-c       Copy a into proj.
+-c
+-        do k = 1,n
+-          do j = 1,m
+-            proj(j,k) = a(j,k)
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-c       ID proj.
+-c
+-        call iddp_id(eps,m,n,proj,krank,list,rnorms)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddp_aid1(eps,n2,n,kranki,proj,krank,list,rnorms)
+-c
+-c       IDs the uppermost kranki x n block of the n2 x n matrix
+-c       input as proj.
+-c
+-c       input:
+-c       eps -- precision of the decomposition to be constructed
+-c       n2 -- first dimension of proj as input
+-c       n -- second dimension of proj as input
+-c       kranki -- number of rows to extract from proj
+-c       proj -- matrix containing the kranki x n block to be ID'd
+-c
+-c       output:
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns
+-c               in the original matrix being ID'd
+-c       krank -- numerical rank of the ID
+-c       list -- indices of the columns in the ID
+-c
+-c       work:
+-c       rnorms -- must be at least n real*8 elements long
+-c
+-        implicit none
+-        integer n,n2,kranki,krank,list(n),j,k
+-        real*8 eps,proj(n2*n),rnorms(n)
+-c
+-c
+-c       Move the uppermost kranki x n block of the n2 x n matrix proj
+-c       to the beginning of proj.
+-c
+-        do k = 1,n
+-          do j = 1,kranki
+-            proj(j+kranki*(k-1)) = proj(j+n2*(k-1))
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-c       ID proj.
+-c
+-        call iddp_id(eps,kranki,n,proj,krank,list,rnorms)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_estrank(eps,m,n,a,w,krank,ra)
+-c
+-c       estimates the numerical rank krank of an m x n matrix a
+-c       to precision eps. This routine applies n2 random vectors
+-c       to a, obtaining ra, where n2 is the greatest integer
+-c       less than or equal to m such that n2 is a positive integer
+-c       power of two. krank is typically about 8 higher than
+-c       the actual numerical rank.
+-c
+-c       input:
+-c       eps -- precision defining the numerical rank
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       a -- matrix whose rank is to be estimated
+-c       w -- initialization array that has been constructed
+-c            by routine idd_frmi
+-c
+-c       output:
+-c       krank -- estimate of the numerical rank of a;
+-c                this routine returns krank = 0 when the actual
+-c                numerical rank is nearly full (that is,
+-c                greater than n - 8 or n2 - 8)
+-c       ra -- product of an n2 x m random matrix and the m x n matrix
+-c             a, where n2 is the greatest integer less than or equal
+-c             to m such that n2 is a positive integer power of two;
+-c             ra doubles as a work array in the present routine, and so
+-c             must be at least n*n2+(n+1)*(n2+1) real*8 elements long
+-c
+-c       _N.B._: ra must be at least n*n2+(n2+1)*(n+1) real*8
+-c               elements long for use in the present routine
+-c               (here, n2 is the greatest integer less than or equal
+-c               to m, such that n2 is a positive integer power of two).
+-c               This routine returns krank = 0 when the actual
+-c               numerical rank is nearly full.
+-c
+-        implicit none
+-        integer m,n,krank,n2,irat,lrat,iscal,lscal,ira,lra,lra2
+-        real*8 eps,a(m,n),ra(*),w(17*m+70)
+-c
+-c
+-c       Extract from the array w initialized by routine idd_frmi
+-c       the greatest integer less than or equal to m that is
+-c       a positive integer power of two.
+-c
+-        n2 = w(2)
+-c
+-c
+-c       Allocate memory in ra.
+-c
+-        lra = 0
+-c
+-        ira = lra+1
+-        lra2 = n2*n
+-        lra = lra+lra2
+-c
+-        irat = lra+1
+-        lrat = n*(n2+1)
+-        lra = lra+lrat
+-c
+-        iscal = lra+1
+-        lscal = n2+1
+-        lra = lra+lscal
+-c
+-        call idd_estrank0(eps,m,n,a,w,n2,krank,ra(ira),ra(irat),
+-     1                    ra(iscal))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_estrank0(eps,m,n,a,w,n2,krank,ra,rat,scal)
+-c
+-c       routine idd_estrank serves as a memory wrapper
+-c       for the present routine. (Please see routine idd_estrank
+-c       for further documentation.)
+-c
+-        implicit none
+-        integer m,n,n2,krank,ifrescal,k,nulls,j
+-        real*8 a(m,n),ra(n2,n),scal(n2+1),eps,residual,
+-     1         w(17*m+70),rat(n,n2+1),ss,ssmax
+-c
+-c
+-c       Apply the random matrix to every column of a, obtaining ra.
+-c
+-        do k = 1,n
+-          call idd_frm(m,n2,w,a(1,k),ra(1,k))
+-        enddo ! k
+-c
+-c
+-c       Compute the sum of squares of the entries in each column of ra
+-c       and the maximum of all such sums.
+-c
+-        ssmax = 0
+-c
+-        do k = 1,n
+-c
+-          ss = 0
+-          do j = 1,m
+-            ss = ss+a(j,k)**2
+-          enddo ! j
+-c
+-          if(ss .gt. ssmax) ssmax = ss
+-c
+-        enddo ! k
+-c
+-c
+-c       Transpose ra to obtain rat.
+-c
+-        call idd_atransposer(n2,n,ra,rat)
+-c
+-c
+-        krank = 0
+-        nulls = 0
+-c
+-c
+-c       Loop until nulls = 7, krank+nulls = n2, or krank+nulls = n.
+-c
+- 1000   continue
+-c
+-c
+-          if(krank .gt. 0) then
+-c
+-c           Apply the previous Householder transformations
+-c           to rat(:,krank+1).
+-c
+-            ifrescal = 0
+-c
+-            do k = 1,krank
+-              call idd_houseapp(n-k+1,rat(1,k),rat(k,krank+1),
+-     1                          ifrescal,scal(k),rat(k,krank+1))
+-            enddo ! k
+-c
+-          endif ! krank .gt. 0
+-c
+-c
+-c         Compute the Householder vector associated
+-c         with rat(krank+1:*,krank+1).
+-c
+-          call idd_house(n-krank,rat(krank+1,krank+1),
+-     1                   residual,rat(1,krank+1),scal(krank+1))
+-          residual = abs(residual)
+-c
+-c
+-          krank = krank+1
+-          if(residual .le. eps*sqrt(ssmax)) nulls = nulls+1
+-c
+-c
+-        if(nulls .lt. 7 .and. krank+nulls .lt. n2
+-     1   .and. krank+nulls .lt. n)
+-     2   goto 1000
+-c
+-c
+-        if(nulls .lt. 7) krank = 0
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_atransposer(m,n,a,at)
+-c
+-c       transposes a to obtain at.
+-c
+-c       input:
+-c       m -- first dimension of a, and second dimension of at
+-c       n -- second dimension of a, and first dimension of at
+-c       a -- matrix to be transposed
+-c
+-c       output:
+-c       at -- transpose of a
+-c
+-        implicit none
+-        integer m,n,j,k
+-        real*8 a(m,n),at(n,m)
+-c
+-c
+-        do k = 1,n
+-          do j = 1,m
+-c
+-            at(k,j) = a(j,k)
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/iddp_asvd.f b/scipy/linalg/src/id_dist/src/iddp_asvd.f
+deleted file mode 100644
+index a3dea4611..000000000
+--- a/scipy/linalg/src/id_dist/src/iddp_asvd.f
++++ /dev/null
+@@ -1,180 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddp_asvd computes the SVD, to a specified precision,
+-c       of an arbitrary matrix. This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine iddp_asvd(lw,eps,m,n,a,winit,krank,iu,iv,is,w,ier)
+-c
+-c       constructs a rank-krank SVD  U Sigma V^T  approximating a
+-c       to precision eps, where U is an m x krank matrix whose
+-c       columns are orthonormal, V is an n x krank matrix whose
+-c       columns are orthonormal, and Sigma is a diagonal krank x krank
+-c       matrix whose entries are all nonnegative.
+-c       The entries of U are stored in w, starting at w(iu);
+-c       the entries of V are stored in w, starting at w(iv).
+-c       The diagonal entries of Sigma are stored in w,
+-c       starting at w(is). This routine uses a randomized algorithm.
+-c
+-c       input:
+-c       lw -- maximum usable length (in real*8 elements)
+-c             of the array w
+-c       eps -- precision of the desired approximation
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       a -- matrix to be approximated; the present routine does not
+-c            alter a
+-c       winit -- initialization array that has been constructed
+-c                by routine idd_frmi
+-c
+-c       output:
+-c       krank -- rank of the SVD constructed
+-c       iu -- index in w of the first entry of the matrix
+-c             of orthonormal left singular vectors of a
+-c       iv -- index in w of the first entry of the matrix
+-c             of orthonormal right singular vectors of a
+-c       is -- index in w of the first entry of the array
+-c             of singular values of a
+-c       w -- array containing the singular values and singular vectors
+-c            of a; w doubles as a work array, and so must be at least
+-c            max( (krank+1)*(3*m+5*n+1)+25*krank**2, (2*n+1)*(n2+1) )
+-c            real*8 elements long, where n2 is the greatest integer
+-c            less than or equal to m, such that n2 is
+-c            a positive integer power of two; krank is the rank output
+-c            by this routine
+-c       ier -- 0 when the routine terminates successfully;
+-c              -1000 when lw is too small;
+-c              other nonzero values when idd_id2svd bombs
+-c
+-c       _N.B._: w must be at least
+-c               max( (krank+1)*(3*m+5*n+1)+25*krank^2, (2*n+1)*(n2+1) )
+-c               real*8 elements long, where n2 is the greatest integer
+-c               less than or equal to m, such that n2 is
+-c               a positive integer power of two;
+-c               krank is the rank output by this routine.
+-c               Also, the algorithm used by this routine is randomized.
+-c
+-        implicit none
+-        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
+-     1          iwork,lwork,k,ier,lw2,iu,iv,is,iui,ivi,isi,lu,lv,ls
+-        real*8 eps,a(m,n),winit(17*m+70),w(*)
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw2 = 0
+-c
+-        ilist = lw2+1
+-        llist = n
+-        lw2 = lw2+llist
+-c
+-        iproj = lw2+1
+-c
+-c
+-c       ID a.
+-c
+-        call iddp_aid(eps,m,n,a,winit,krank,w(ilist),w(iproj))
+-c
+-c
+-        if(krank .gt. 0) then
+-c
+-c
+-c         Allocate more memory in w.
+-c
+-          lproj = krank*(n-krank)
+-          lw2 = lw2+lproj
+-c
+-          icol = lw2+1
+-          lcol = m*krank
+-          lw2 = lw2+lcol
+-c
+-          iui = lw2+1
+-          lu = m*krank
+-          lw2 = lw2+lu
+-c
+-          ivi = lw2+1
+-          lv = n*krank
+-          lw2 = lw2+lv
+-c
+-          isi = lw2+1
+-          ls = krank
+-          lw2 = lw2+ls
+-c
+-          iwork = lw2+1
+-          lwork = (krank+1)*(m+3*n)+26*krank**2
+-          lw2 = lw2+lwork
+-c
+-c
+-          if(lw .lt. lw2) then
+-            ier = -1000
+-            return
+-          endif
+-c
+-c
+-          call iddp_asvd0(m,n,a,krank,w(ilist),w(iproj),
+-     1                    w(iui),w(ivi),w(isi),ier,w(icol),w(iwork))
+-          if(ier .ne. 0) return
+-c
+-c
+-          iu = 1
+-          iv = iu+lu
+-          is = iv+lv
+-c
+-c
+-c         Copy the singular values and singular vectors
+-c         into their proper locations.
+-c
+-          do k = 1,lu
+-            w(iu+k-1) = w(iui+k-1)
+-          enddo ! k
+-c
+-          do k = 1,lv
+-            w(iv+k-1) = w(ivi+k-1)
+-          enddo ! k
+-c
+-          do k = 1,ls
+-            w(is+k-1) = w(isi+k-1)
+-          enddo ! k
+-c
+-c
+-        endif ! krank .gt. 0
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddp_asvd0(m,n,a,krank,list,proj,u,v,s,ier,
+-     1                        col,work)
+-c
+-c       routine iddp_asvd serves as a memory wrapper
+-c       for the present routine (please see routine iddp_asvd
+-c       for further documentation).
+-c
+-        implicit none
+-        integer m,n,krank,list(n),ier
+-        real*8 a(m,n),u(m,krank),v(n,krank),
+-     1         s(krank),proj(krank,n-krank),col(m,krank),
+-     2         work((krank+1)*(m+3*n)+26*krank**2)
+-c
+-c
+-c       Collect together the columns of a indexed by list into col.
+-c
+-        call idd_copycols(m,n,a,krank,list,col)
+-c
+-c
+-c       Convert the ID to an SVD.
+-c
+-        call idd_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/iddp_rid.f b/scipy/linalg/src/id_dist/src/iddp_rid.f
+deleted file mode 100644
+index 93b255f15..000000000
+--- a/scipy/linalg/src/id_dist/src/iddp_rid.f
++++ /dev/null
+@@ -1,376 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddp_rid computes the ID, to a specified precision,
+-c       of a matrix specified by a routine for applying its transpose
+-c       to arbitrary vectors. This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine iddp_rid(lproj,eps,m,n,matvect,p1,p2,p3,p4,
+-     1                      krank,list,proj,ier)
+-c
+-c       computes the ID of a, i.e., lists in list the indices
+-c       of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                        krank
+-c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
+-c                         l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon dimensioned epsilon(m,n-krank)
+-c       such that the greatest singular value of epsilon
+-c       <= the greatest singular value of a * eps.
+-c
+-c       input:
+-c       lproj -- maximum usable length (in real*8 elements)
+-c                of the array proj
+-c       eps -- precision to which the ID is to be computed
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       matvect -- routine which applies the transpose
+-c                  of the matrix to be ID'd to an arbitrary vector;
+-c                  this routine must have a calling sequence
+-c                  of the form
+-c
+-c                  matvect(m,x,n,y,p1,p2,p3,p4),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the transpose
+-c                  of the matrix is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the transposed matrix and x,
+-c                  and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvect
+-c       p2 -- parameter to be passed to routine matvect
+-c       p3 -- parameter to be passed to routine matvect
+-c       p4 -- parameter to be passed to routine matvect
+-c
+-c       output:
+-c       krank -- numerical rank
+-c       list -- indices of the columns in the ID
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns
+-c               in the original matrix being ID'd;
+-c               the present routine uses proj as a work array, too, so
+-c               proj must be at least m+1 + 2*n*(krank+1) real*8
+-c               elements long, where krank is the rank output
+-c               by the present routine
+-c       ier -- 0 when the routine terminates successfully;
+-c              -1000 when lproj is too small
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c               proj must be at least m+1 + 2*n*(krank+1) real*8
+-c               elements long, where krank is the rank output
+-c               by the present routine.
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,n,list(n),krank,lw,iwork,lwork,ira,kranki,lproj,
+-     1          lra,ier,k
+-        real*8 eps,p1,p2,p3,p4,proj(*)
+-        external matvect
+-c
+-c
+-        ier = 0
+-c
+-c
+-c       Allocate memory in proj.
+-c
+-        lw = 0
+-c
+-        iwork = lw+1
+-        lwork = m+2*n+1
+-        lw = lw+lwork
+-c
+-        ira = lw+1
+-c
+-c
+-c       Find the rank of a.
+-c
+-        lra = lproj-lwork
+-        call idd_findrank(lra,eps,m,n,matvect,p1,p2,p3,p4,
+-     1                    kranki,proj(ira),ier,proj(iwork))
+-        if(ier .ne. 0) return
+-c
+-c
+-        if(lproj .lt. lwork+2*kranki*n) then
+-          ier = -1000
+-          return
+-        endif
+-c
+-c
+-c       Transpose ra.
+-c
+-        call idd_rtransposer(n,kranki,proj(ira),proj(ira+kranki*n))
+-c
+-c
+-c       Move the tranposed matrix to the beginning of proj.
+-c
+-        do k = 1,kranki*n
+-          proj(k) = proj(ira+kranki*n+k-1)
+-        enddo ! k
+-c
+-c
+-c       ID the transposed matrix.
+-c
+-        call iddp_id(eps,kranki,n,proj,krank,list,proj(1+kranki*n))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_findrank(lra,eps,m,n,matvect,p1,p2,p3,p4,
+-     1                          krank,ra,ier,w)
+-c
+-c       estimates the numerical rank krank of a matrix a to precision
+-c       eps, where the routine matvect applies the transpose of a
+-c       to an arbitrary vector. This routine applies the transpose of a
+-c       to krank random vectors, and returns the resulting vectors
+-c       as the columns of ra.
+-c
+-c       input:
+-c       lra -- maximum usable length (in real*8 elements) of array ra
+-c       eps -- precision defining the numerical rank
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       matvect -- routine which applies the transpose
+-c                  of the matrix whose rank is to be estimated
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matvect(m,x,n,y,p1,p2,p3,p4),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the transpose
+-c                  of the matrix is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the transposed matrix and x,
+-c                  and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvect
+-c       p2 -- parameter to be passed to routine matvect
+-c       p3 -- parameter to be passed to routine matvect
+-c       p4 -- parameter to be passed to routine matvect
+-c
+-c       output:
+-c       krank -- estimate of the numerical rank of a
+-c       ra -- product of the transpose of a and a matrix whose entries
+-c             are pseudorandom realizations of i.i.d. random numbers,
+-c             uniformly distributed on [0,1];
+-c             ra must be at least 2*n*krank real*8 elements long
+-c       ier -- 0 when the routine terminates successfully;
+-c              -1000 when lra is too small
+-c
+-c       work:
+-c       w -- must be at least m+2*n+1 real*8 elements long
+-c
+-c       _N.B._: ra must be at least 2*n*krank real*8 elements long.
+-c               Also, the algorithm used by this routine is randomized.
+-c
+-        implicit none
+-        integer m,n,lw,krank,ix,lx,iy,ly,iscal,lscal,lra,ier
+-        real*8 eps,p1,p2,p3,p4,ra(n,*),w(m+2*n+1)
+-        external matvect
+-c
+-c
+-        lw = 0
+-c
+-        ix = lw+1
+-        lx = m
+-        lw = lw+lx
+-c
+-        iy = lw+1
+-        ly = n
+-        lw = lw+ly
+-c
+-        iscal = lw+1
+-        lscal = n+1
+-        lw = lw+lscal
+-c
+-c
+-        call idd_findrank0(lra,eps,m,n,matvect,p1,p2,p3,p4,
+-     1                     krank,ra,ier,w(ix),w(iy),w(iscal))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_findrank0(lra,eps,m,n,matvect,p1,p2,p3,p4,
+-     1                           krank,ra,ier,x,y,scal)
+-c
+-c       routine idd_findrank serves as a memory wrapper
+-c       for the present routine. (Please see routine idd_findrank
+-c       for further documentation.)
+-c
+-        implicit none
+-        integer m,n,krank,ifrescal,k,lra,ier
+-        real*8 x(m),ra(n,2,*),p1,p2,p3,p4,scal(n+1),y(n),eps,residual,
+-     1         enorm
+-        external matvect
+-c
+-c
+-        ier = 0
+-c
+-c
+-        krank = 0
+-c
+-c
+-c       Loop until the relative residual is greater than eps,
+-c       or krank = m or krank = n.
+-c
+- 1000   continue
+-c
+-c
+-          if(lra .lt. n*2*(krank+1)) then
+-            ier = -1000
+-            return
+-          endif
+-c
+-c
+-c         Apply the transpose of a to a random vector.
+-c
+-          call id_srand(m,x)
+-          call matvect(m,x,n,ra(1,1,krank+1),p1,p2,p3,p4)
+-c
+-          do k = 1,n
+-            y(k) = ra(k,1,krank+1)
+-          enddo ! k
+-c
+-c
+-          if(krank .eq. 0) then
+-c
+-c           Compute the Euclidean norm of y.
+-c
+-            enorm = 0
+-c
+-            do k = 1,n
+-              enorm = enorm + y(k)**2
+-            enddo ! k
+-c
+-            enorm = sqrt(enorm)
+-c
+-          endif ! krank .eq. 0
+-c
+-c
+-          if(krank .gt. 0) then
+-c
+-c           Apply the previous Householder transformations to y.
+-c
+-            ifrescal = 0
+-c
+-            do k = 1,krank
+-              call idd_houseapp(n-k+1,ra(1,2,k),y(k),
+-     1                          ifrescal,scal(k),y(k))
+-            enddo ! k
+-c
+-          endif ! krank .gt. 0
+-c
+-c
+-c         Compute the Householder vector associated with y.
+-c
+-          call idd_house(n-krank,y(krank+1),
+-     1                   residual,ra(1,2,krank+1),scal(krank+1))
+-          residual = abs(residual)
+-c
+-c
+-          krank = krank+1
+-c
+-c
+-        if(residual .gt. eps*enorm
+-     1   .and. krank .lt. m .and. krank .lt. n)
+-     2   goto 1000
+-c
+-c
+-c       Delete the Householder vectors from the array ra.
+-c
+-        call idd_crunch(n,krank,ra)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_crunch(n,l,a)
+-c
+-c       removes every other block of n entries from a vector.
+-c
+-c       input:
+-c       n -- length of each block to remove
+-c       l -- half of the total number of blocks
+-c       a -- original array
+-c
+-c       output:
+-c       a -- array with every other block of n entries removed
+-c
+-        implicit none
+-        integer j,k,n,l
+-        real*8 a(n,2*l)
+-c
+-c
+-        do j = 2,l
+-          do k = 1,n
+-c
+-            a(k,j) = a(k,2*j-1)
+-c
+-          enddo ! k
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idd_rtransposer(m,n,a,at)
+-c
+-c       transposes a to obtain at.
+-c
+-c       input:
+-c       m -- first dimension of a, and second dimension of at
+-c       n -- second dimension of a, and first dimension of at
+-c       a -- matrix to be transposed
+-c
+-c       output:
+-c       at -- transpose of a
+-c
+-        implicit none
+-        integer m,n,j,k
+-        real*8 a(m,n),at(n,m)
+-c
+-c
+-        do k = 1,n
+-          do j = 1,m
+-c
+-            at(k,j) = a(j,k)
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/iddp_rsvd.f b/scipy/linalg/src/id_dist/src/iddp_rsvd.f
+deleted file mode 100644
+index 8af9ba04c..000000000
+--- a/scipy/linalg/src/id_dist/src/iddp_rsvd.f
++++ /dev/null
+@@ -1,216 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddp_rsvd computes the SVD, to a specified precision,
+-c       of a matrix specified by routines for applying the matrix
+-c       and its transpose to arbitrary vectors.
+-c       This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine iddp_rsvd(lw,eps,m,n,matvect,p1t,p2t,p3t,p4t,
+-     1                       matvec,p1,p2,p3,p4,krank,iu,iv,is,w,ier)
+-c
+-c       constructs a rank-krank SVD  U Sigma V^T  approximating a
+-c       to precision eps, where matvect is a routine which applies a^T
+-c       to an arbitrary vector, and matvec is a routine
+-c       which applies a to an arbitrary vector; U is an m x krank
+-c       matrix whose columns are orthonormal, V is an n x krank
+-c       matrix whose columns are orthonormal, and Sigma is a diagonal
+-c       krank x krank matrix whose entries are all nonnegative.
+-c       The entries of U are stored in w, starting at w(iu);
+-c       the entries of V are stored in w, starting at w(iv).
+-c       The diagonal entries of Sigma are stored in w,
+-c       starting at w(is). This routine uses a randomized algorithm.
+-c
+-c       input:
+-c       lw -- maximum usable length (in real*8 elements)
+-c             of the array w
+-c       eps -- precision of the desired approximation
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       matvect -- routine which applies the transpose
+-c                  of the matrix to be SVD'd
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matvect(m,x,n,y,p1t,p2t,p3t,p4t),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the transpose
+-c                  of the matrix is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the transposed matrix and x,
+-c                  and p1t, p2t, p3t, and p4t are user-specified
+-c                  parameters
+-c       p1t -- parameter to be passed to routine matvect
+-c       p2t -- parameter to be passed to routine matvect
+-c       p3t -- parameter to be passed to routine matvect
+-c       p4t -- parameter to be passed to routine matvect
+-c       matvec -- routine which applies the matrix to be SVD'd
+-c                 to an arbitrary vector; this routine must have
+-c                 a calling sequence of the form
+-c
+-c                 matvec(n,x,m,y,p1,p2,p3,p4),
+-c
+-c                 where n is the length of x,
+-c                 x is the vector to which the matrix is to be applied,
+-c                 m is the length of y,
+-c                 y is the product of the matrix and x,
+-c                 and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvec
+-c       p2 -- parameter to be passed to routine matvec
+-c       p3 -- parameter to be passed to routine matvec
+-c       p4 -- parameter to be passed to routine matvec
+-c
+-c       output:
+-c       krank -- rank of the SVD constructed
+-c       iu -- index in w of the first entry of the matrix
+-c             of orthonormal left singular vectors of a
+-c       iv -- index in w of the first entry of the matrix
+-c             of orthonormal right singular vectors of a
+-c       is -- index in w of the first entry of the array
+-c             of singular values of a
+-c       w -- array containing the singular values and singular vectors
+-c            of a; w doubles as a work array, and so must be at least
+-c            (krank+1)*(3*m+5*n+1)+25*krank**2 real*8 elements long,
+-c            where krank is the rank returned by the present routine
+-c       ier -- 0 when the routine terminates successfully;
+-c              -1000 when lw is too small;
+-c              other nonzero values when idd_id2svd bombs
+-c
+-c       _N.B._: w must be at least (krank+1)*(3*m+5*n+1)+25*krank**2
+-c               real*8 elements long, where krank is the rank
+-c               returned by the present routine. Also, the algorithm
+-c               used by the present routine is randomized.
+-c
+-        implicit none
+-        integer m,n,krank,lw,lw2,ilist,llist,iproj,icol,lcol,lp,
+-     1          iwork,lwork,ier,lproj,iu,iv,is,lu,lv,ls,iui,ivi,isi,k
+-        real*8 eps,p1t,p2t,p3t,p4t,p1,p2,p3,p4,w(*)
+-        external matvect,matvec
+-c
+-c
+-c       Allocate some memory.
+-c
+-        lw2 = 0
+-c
+-        ilist = lw2+1
+-        llist = n
+-        lw2 = lw2+llist
+-c
+-        iproj = lw2+1
+-c
+-c
+-c       ID a.
+-c
+-        lp = lw-lw2
+-        call iddp_rid(lp,eps,m,n,matvect,p1t,p2t,p3t,p4t,krank,
+-     1                w(ilist),w(iproj),ier)
+-        if(ier .ne. 0) return
+-c
+-c
+-        if(krank .gt. 0) then
+-c
+-c
+-c         Allocate more memory.
+-c
+-          lproj = krank*(n-krank)
+-          lw2 = lw2+lproj
+-c
+-          icol = lw2+1
+-          lcol = m*krank
+-          lw2 = lw2+lcol
+-c
+-          iui = lw2+1
+-          lu = m*krank
+-          lw2 = lw2+lu
+-c
+-          ivi = lw2+1
+-          lv = n*krank
+-          lw2 = lw2+lv
+-c
+-          isi = lw2+1
+-          ls = krank
+-          lw2 = lw2+ls
+-c
+-          iwork = lw2+1
+-          lwork = (krank+1)*(m+3*n)+26*krank**2
+-          lw2 = lw2+lwork
+-c
+-c
+-          if(lw .lt. lw2) then
+-            ier = -1000
+-            return
+-          endif
+-c
+-c
+-          call iddp_rsvd0(m,n,matvect,p1t,p2t,p3t,p4t,
+-     1                    matvec,p1,p2,p3,p4,krank,w(iui),w(ivi),
+-     2                    w(isi),ier,w(ilist),w(iproj),w(icol),
+-     3                    w(iwork))
+-          if(ier .ne. 0) return
+-c
+-c
+-          iu = 1
+-          iv = iu+lu
+-          is = iv+lv
+-c
+-c
+-c         Copy the singular values and singular vectors
+-c         into their proper locations.
+-c
+-          do k = 1,lu
+-            w(iu+k-1) = w(iui+k-1)
+-          enddo ! k
+-c
+-          do k = 1,lv
+-            w(iv+k-1) = w(ivi+k-1)
+-          enddo ! k
+-c
+-          do k = 1,ls
+-            w(is+k-1) = w(isi+k-1)
+-          enddo ! k
+-c
+-c
+-        endif ! krank .gt. 0
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddp_rsvd0(m,n,matvect,p1t,p2t,p3t,p4t,
+-     1                        matvec,p1,p2,p3,p4,krank,u,v,s,ier,
+-     2                        list,proj,col,work)
+-c
+-c       routine iddp_rsvd serves as a memory wrapper
+-c       for the present routine (please see routine iddp_rsvd
+-c       for further documentation).
+-c
+-        implicit none
+-        integer m,n,krank,list(n),ier
+-        real*8 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
+-     1         s(krank),proj(krank,n-krank),col(m*krank),
+-     2         work((krank+1)*(m+3*n)+26*krank**2)
+-        external matvect,matvec
+-c
+-c
+-c       Collect together the columns of a indexed by list into col.
+-c
+-        call idd_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,col,work)
+-c
+-c
+-c       Convert the ID to an SVD.
+-c
+-        call idd_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/iddr_aid.f b/scipy/linalg/src/id_dist/src/iddr_aid.f
+deleted file mode 100644
+index 2dc811148..000000000
+--- a/scipy/linalg/src/id_dist/src/iddr_aid.f
++++ /dev/null
+@@ -1,208 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddr_aid computes the ID, to a specified rank,
+-c       of an arbitrary matrix. This routine is randomized.
+-c
+-c       routine iddr_aidi initializes routine iddr_aid.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine iddr_aid(m,n,a,krank,w,list,proj)
+-c
+-c       computes the ID of the matrix a, i.e., lists in list
+-c       the indices of krank columns of a such that 
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                       min(m,n,krank)
+-c       a(j,list(k))  =     Sigma      a(j,list(l)) * proj(l,k-krank)(*)
+-c                            l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
+-c       whose norm is (hopefully) minimized by the pivoting procedure.
+-c
+-c       input:
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       a -- matrix to be ID'd; the present routine does not alter a
+-c       krank -- rank of the ID to be constructed
+-c       w -- initialization array that routine iddr_aidi
+-c            has constructed
+-c
+-c       output:
+-c       list -- indices of the columns in the ID
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns
+-c               in the original matrix being ID'd
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,n,krank,list(n),lw,ir,lr,lw2,iw
+-        real*8 a(m,n),proj(krank*(n-krank)),w((2*krank+17)*n+27*m+100)
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw = 0
+-c
+-        iw = lw+1
+-        lw2 = 27*m+100+n
+-        lw = lw+lw2
+-c
+-        ir = lw+1
+-        lr = (krank+8)*2*n
+-        lw = lw+lr
+-c
+-c
+-        call iddr_aid0(m,n,a,krank,w(iw),list,proj,w(ir))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddr_aid0(m,n,a,krank,w,list,proj,r)
+-c
+-c       routine iddr_aid serves as a memory wrapper
+-c       for the present routine
+-c       (see iddr_aid for further documentation).
+-c
+-        implicit none
+-        integer k,l,m,n2,n,krank,list(n),mn,lproj
+-        real*8 a(m,n),r(krank+8,2*n),proj(krank,n-krank),
+-     1         w(27*m+100+n)
+-c
+-c       Please note that the second dimension of r is 2*n
+-c       (instead of n) so that if krank+8 >= m/2, then
+-c       we can copy the whole of a into r.
+-c
+-c
+-c       Retrieve the number of random test vectors
+-c       and the greatest integer less than m that is
+-c       a positive integer power of two.
+-c
+-        l = w(1)
+-        n2 = w(2)
+-c
+-c
+-        if(l .lt. n2 .and. l .le. m) then
+-c
+-c         Apply the random matrix.
+-c
+-          do k = 1,n
+-            call idd_sfrm(l,m,n2,w(11),a(1,k),r(1,k))
+-          enddo ! k
+-c
+-c         ID r.
+-c
+-          call iddr_id(l,n,r,krank,list,w(26*m+101))
+-c
+-c         Retrieve proj from r.
+-c
+-          lproj = krank*(n-krank)
+-          call iddr_copydarr(lproj,r,proj)
+-c
+-        endif
+-c
+-c
+-        if(l .ge. n2 .or. l .gt. m) then
+-c
+-c         ID a directly.
+-c
+-          mn = m*n
+-          call iddr_copydarr(mn,a,r)
+-          call iddr_id(m,n,r,krank,list,w(26*m+101))
+-c
+-c         Retrieve proj from r.
+-c
+-          lproj = krank*(n-krank)
+-          call iddr_copydarr(lproj,r,proj)
+-c
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddr_copydarr(n,a,b)
+-c
+-c       copies a into b.
+-c
+-c       input:
+-c       n -- length of a and b
+-c       a -- array to copy into b
+-c
+-c       output:
+-c       b -- copy of a
+-c
+-        implicit none
+-        integer n,k
+-        real*8 a(n),b(n)
+-c
+-c
+-        do k = 1,n
+-          b(k) = a(k)
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddr_aidi(m,n,krank,w)
+-c
+-c       initializes the array w for using routine iddr_aid.
+-c
+-c       input:
+-c       m -- number of rows in the matrix to be ID'd
+-c       n -- number of columns in the matrix to be ID'd
+-c       krank -- rank of the ID to be constructed
+-c
+-c       output:
+-c       w -- initialization array for using routine iddr_aid
+-c
+-        implicit none
+-        integer m,n,krank,l,n2
+-        real*8 w((2*krank+17)*n+27*m+100)
+-c
+-c
+-c       Set the number of random test vectors to 8 more than the rank.
+-c
+-        l = krank+8
+-        w(1) = l
+-c
+-c
+-c       Initialize the rest of the array w.
+-c
+-        n2 = 0
+-        if(l .le. m) call idd_sfrmi(l,m,n2,w(11))
+-        w(2) = n2
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/iddr_asvd.f b/scipy/linalg/src/id_dist/src/iddr_asvd.f
+deleted file mode 100644
+index 9641f0cd6..000000000
+--- a/scipy/linalg/src/id_dist/src/iddr_asvd.f
++++ /dev/null
+@@ -1,114 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddr_aid computes the SVD, to a specified rank,
+-c       of an arbitrary matrix. This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine iddr_asvd(m,n,a,krank,w,u,v,s,ier)
+-c
+-c       constructs a rank-krank SVD  u diag(s) v^T  approximating a,
+-c       where u is an m x krank matrix whose columns are orthonormal,
+-c       v is an n x krank matrix whose columns are orthonormal,
+-c       and diag(s) is a diagonal krank x krank matrix whose entries
+-c       are all nonnegative. This routine uses a randomized algorithm.
+-c
+-c       input:
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       a -- matrix to be decomposed; the present routine does not
+-c            alter a
+-c       krank -- rank of the SVD being constructed
+-c       w -- initialization array that routine iddr_aidi
+-c            has constructed (for use in the present routine, w must
+-c            be at least (2*krank+28)*m+(6*krank+21)*n+25*krank**2+100
+-c            real*8 elements long)
+-c
+-c       output:
+-c       u -- matrix of orthonormal left singular vectors of a
+-c       v -- matrix of orthonormal right singular vectors of a
+-c       s -- array of singular values of a
+-c       ier -- 0 when the routine terminates successfully;
+-c              nonzero otherwise
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c
+-        implicit none
+-        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
+-     1          iwork,lwork,iwinit,lwinit,ier
+-        real*8 a(m,n),u(m,krank),v(n,krank),s(krank),
+-     1         w((2*krank+28)*m+(6*krank+21)*n+25*krank**2+100)
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw = 0
+-c
+-        iwinit = lw+1
+-        lwinit = (2*krank+17)*n+27*m+100
+-        lw = lw+lwinit
+-c
+-        ilist = lw+1
+-        llist = n
+-        lw = lw+llist
+-c
+-        iproj = lw+1
+-        lproj = krank*(n-krank)
+-        lw = lw+lproj
+-c
+-        icol = lw+1
+-        lcol = m*krank
+-        lw = lw+lcol
+-c
+-        iwork = lw+1
+-        lwork = (krank+1)*(m+3*n)+26*krank**2
+-        lw = lw+lwork
+-c
+-c
+-        call iddr_asvd0(m,n,a,krank,w(iwinit),u,v,s,ier,
+-     1                  w(ilist),w(iproj),w(icol),w(iwork))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddr_asvd0(m,n,a,krank,winit,u,v,s,ier,
+-     1                        list,proj,col,work)
+-c
+-c       routine iddr_asvd serves as a memory wrapper
+-c       for the present routine (please see routine iddr_asvd
+-c       for further documentation).
+-c
+-        implicit none
+-        integer m,n,krank,list(n),ier
+-        real*8 a(m,n),u(m,krank),v(n,krank),s(krank),
+-     1         proj(krank,n-krank),col(m*krank),
+-     2         winit((2*krank+17)*n+27*m+100),
+-     3         work((krank+1)*(m+3*n)+26*krank**2)
+-c
+-c
+-c       ID a.
+-c
+-        call iddr_aid(m,n,a,krank,winit,list,proj)
+-c
+-c
+-c       Collect together the columns of a indexed by list into col.
+-c
+-        call idd_copycols(m,n,a,krank,list,col)
+-c
+-c
+-c       Convert the ID to an SVD.
+-c
+-        call idd_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/iddr_rid.f b/scipy/linalg/src/id_dist/src/iddr_rid.f
+deleted file mode 100644
+index eb96c145a..000000000
+--- a/scipy/linalg/src/id_dist/src/iddr_rid.f
++++ /dev/null
+@@ -1,155 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddr_rid computes the ID, to a specified rank,
+-c       of a matrix specified by a routine for applying its transpose
+-c       to arbitrary vectors. This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine iddr_rid(m,n,matvect,p1,p2,p3,p4,krank,list,proj)
+-c
+-c       computes the ID of a matrix "a" specified by
+-c       the routine matvect -- matvect must apply the transpose
+-c       of the matrix being ID'd to an arbitrary vector --
+-c       i.e., the present routine lists in list the indices
+-c       of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                       min(m,n,krank)
+-c       a(j,list(k))  =     Sigma      a(j,list(l)) * proj(l,k-krank)(*)
+-c                            l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
+-c       whose norm is (hopefully) minimized by the pivoting procedure.
+-c
+-c       input:
+-c       m -- number of rows in the matrix to be ID'd
+-c       n -- number of columns in the matrix to be ID'd
+-c       matvect -- routine which applies the transpose
+-c                  of the matrix to be ID'd to an arbitrary vector;
+-c                  this routine must have a calling sequence
+-c                  of the form
+-c
+-c                  matvect(m,x,n,y,p1,p2,p3,p4),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the transpose
+-c                  of the matrix is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the transposed matrix and x,
+-c                  and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvect
+-c       p2 -- parameter to be passed to routine matvect
+-c       p3 -- parameter to be passed to routine matvect
+-c       p4 -- parameter to be passed to routine matvect
+-c       krank -- rank of the ID to be constructed
+-c
+-c       output:
+-c       list -- indices of the columns in the ID
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns
+-c               in the original matrix being ID'd;
+-c               proj doubles as a work array in the present routine, so
+-c               proj must be at least m+(krank+3)*n real*8 elements
+-c               long
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c               proj must be at least m+(krank+3)*n real*8 elements
+-c               long.
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,n,krank,list(n),lw,ix,lx,iy,ly,ir,lr
+-        real*8 p1,p2,p3,p4,proj(m+(krank+3)*n)
+-        external matvect
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw = 0
+-c
+-        ir = lw+1
+-        lr = (krank+2)*n
+-        lw = lw+lr
+-c
+-        ix = lw+1
+-        lx = m
+-        lw = lw+lx
+-c
+-        iy = lw+1
+-        ly = n
+-        lw = lw+ly
+-c
+-c
+-        call iddr_ridall0(m,n,matvect,p1,p2,p3,p4,krank,
+-     1                    list,proj(ir),proj(ix),proj(iy))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddr_ridall0(m,n,matvect,p1,p2,p3,p4,krank,
+-     1                          list,r,x,y)
+-c
+-c       routine iddr_ridall serves as a memory wrapper
+-c       for the present routine
+-c       (see iddr_ridall for further documentation).
+-c
+-        implicit none
+-        integer j,k,l,m,n,krank,list(n)
+-        real*8 x(m),y(n),p1,p2,p3,p4,r(krank+2,n)
+-        external matvect
+-c
+-c
+-c       Set the number of random test vectors to 2 more than the rank.
+-c
+-        l = krank+2
+-c
+-c       Apply the transpose of the original matrix to l random vectors.
+-c
+-        do j = 1,l
+-c
+-c         Generate a random vector.
+-c
+-          call id_srand(m,x)
+-c
+-c         Apply the transpose of the matrix to x, obtaining y.
+-c
+-          call matvect(m,x,n,y,p1,p2,p3,p4)
+-c
+-c         Copy y into row j of r.
+-c
+-          do k = 1,n
+-            r(j,k) = y(k)
+-          enddo ! k
+-c
+-        enddo ! j
+-c
+-c
+-c       ID r.
+-c
+-        call iddr_id(l,n,r,krank,list,y)
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/iddr_rsvd.f b/scipy/linalg/src/id_dist/src/iddr_rsvd.f
+deleted file mode 100644
+index 000ce8693..000000000
+--- a/scipy/linalg/src/id_dist/src/iddr_rsvd.f
++++ /dev/null
+@@ -1,157 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine iddr_rsvd computes the SVD, to a specified rank,
+-c       of a matrix specified by routines for applying the matrix
+-c       and its transpose to arbitrary vectors.
+-c       This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine iddr_rsvd(m,n,matvect,p1t,p2t,p3t,p4t,
+-     1                       matvec,p1,p2,p3,p4,krank,u,v,s,ier,w)
+-c
+-c       constructs a rank-krank SVD  u diag(s) v^T  approximating a,
+-c       where matvect is a routine which applies a^T
+-c       to an arbitrary vector, and matvec is a routine
+-c       which applies a to an arbitrary vector;
+-c       u is an m x krank matrix whose columns are orthonormal,
+-c       v is an n x krank matrix whose columns are orthonormal,
+-c       and diag(s) is a diagonal krank x krank matrix whose entries
+-c       are all nonnegative. This routine uses a randomized algorithm.
+-c
+-c       input:
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       matvect -- routine which applies the transpose
+-c                  of the matrix to be SVD'd
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matvect(m,x,n,y,p1t,p2t,p3t,p4t),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the transpose
+-c                  of the matrix is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the transposed matrix and x,
+-c                  and p1t, p2t, p3t, and p4t are user-specified
+-c                  parameters
+-c       p1t -- parameter to be passed to routine matvect
+-c       p2t -- parameter to be passed to routine matvect
+-c       p3t -- parameter to be passed to routine matvect
+-c       p4t -- parameter to be passed to routine matvect
+-c       matvec -- routine which applies the matrix to be SVD'd
+-c                 to an arbitrary vector; this routine must have
+-c                 a calling sequence of the form
+-c
+-c                 matvec(n,x,m,y,p1,p2,p3,p4),
+-c
+-c                 where n is the length of x,
+-c                 x is the vector to which the matrix is to be applied,
+-c                 m is the length of y,
+-c                 y is the product of the matrix and x,
+-c                 and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvec
+-c       p2 -- parameter to be passed to routine matvec
+-c       p3 -- parameter to be passed to routine matvec
+-c       p4 -- parameter to be passed to routine matvec
+-c       krank -- rank of the SVD being constructed
+-c
+-c       output:
+-c       u -- matrix of orthonormal left singular vectors of a
+-c       v -- matrix of orthonormal right singular vectors of a
+-c       s -- array of singular values of a
+-c       ier -- 0 when the routine terminates successfully;
+-c              nonzero otherwise
+-c
+-c       work:
+-c       w -- must be at least (krank+1)*(2*m+4*n)+25*krank**2
+-c            real*8 elements long
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c
+-        implicit none
+-        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
+-     1          iwork,lwork,ier
+-        real*8 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
+-     1         s(krank),w((krank+1)*(2*m+4*n)+25*krank**2)
+-        external matvect,matvec
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw = 0
+-c
+-        ilist = lw+1
+-        llist = n
+-        lw = lw+llist
+-c
+-        iproj = lw+1
+-        lproj = krank*(n-krank)
+-        lw = lw+lproj
+-c
+-        icol = lw+1
+-        lcol = m*krank
+-        lw = lw+lcol
+-c
+-        iwork = lw+1
+-        lwork = (krank+1)*(m+3*n)+26*krank**2
+-        lw = lw+lwork
+-c
+-c
+-        call iddr_rsvd0(m,n,matvect,p1t,p2t,p3t,p4t,
+-     1                  matvec,p1,p2,p3,p4,krank,u,v,s,ier,
+-     2                  w(ilist),w(iproj),w(icol),w(iwork))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine iddr_rsvd0(m,n,matvect,p1t,p2t,p3t,p4t,
+-     1                        matvec,p1,p2,p3,p4,krank,u,v,s,ier,
+-     2                        list,proj,col,work)
+-c
+-c       routine iddr_rsvd serves as a memory wrapper
+-c       for the present routine (please see routine iddr_rsvd
+-c       for further documentation).
+-c
+-        implicit none
+-        integer m,n,krank,list(n),ier,k
+-        real*8 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
+-     1         s(krank),proj(krank*(n-krank)),col(m*krank),
+-     2         work((krank+1)*(m+3*n)+26*krank**2)
+-        external matvect,matvec
+-c
+-c
+-c       ID a.
+-c
+-        call iddr_rid(m,n,matvect,p1t,p2t,p3t,p4t,krank,list,work)
+-c
+-c
+-c       Retrieve proj from work.
+-c
+-        do k = 1,krank*(n-krank)
+-          proj(k) = work(k)
+-        enddo ! k
+-c
+-c
+-c       Collect together the columns of a indexed by list into col.
+-c
+-        call idd_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,col,work)
+-c
+-c
+-c       Convert the ID to an SVD.
+-c
+-        call idd_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idz_frm.f b/scipy/linalg/src/id_dist/src/idz_frm.f
+deleted file mode 100644
+index 93c4d8ec7..000000000
+--- a/scipy/linalg/src/id_dist/src/idz_frm.f
++++ /dev/null
+@@ -1,419 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idz_frm transforms a vector via a composition
+-c       of Rokhlin's random transform, random subselection, and an FFT.
+-c
+-c       routine idz_sfrm transforms a vector into a vector
+-c       of specified length via a composition
+-c       of Rokhlin's random transform, random subselection, and an FFT.
+-c
+-c       routine idz_frmi initializes routine idz_frm.
+-c
+-c       routine idz_sfrmi initializes routine idz_sfrm.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idz_frm(m,n,w,x,y)
+-c
+-c       transforms x into y via a composition
+-c       of Rokhlin's random transform, random subselection, and an FFT.
+-c       In contrast to routine idz_sfrm, the present routine works best
+-c       when the length of the transformed vector is the integer n
+-c       output by routine idz_frmi, or when the length
+-c       is not specified, but instead determined a posteriori
+-c       using the output of the present routine. The transformed vector
+-c       output by the present routine is randomly permuted.
+-c
+-c       input:
+-c       m -- length of x
+-c       n -- greatest integer expressible as a positive integer power
+-c            of 2 that is less than or equal to m, as obtained
+-c            from the routine idz_frmi; n is the length of y
+-c       w -- initialization array constructed by routine idz_frmi
+-c       x -- vector to be transformed
+-c
+-c       output:
+-c       y -- transform of x
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,iw,n,k
+-        complex*16 w(17*m+70),x(m),y(n)
+-c
+-c
+-c       Apply Rokhlin's random transformation to x, obtaining
+-c       w(16*m+71 : 17*m+70).
+-c
+-        iw = w(3+m+n)
+-        call idz_random_transf(x,w(16*m+70+1),w(iw))
+-c
+-c
+-c       Subselect from  w(16*m+71 : 17*m+70)  to obtain y.
+-c
+-        call idz_subselect(n,w(3),m,w(16*m+70+1),y)
+-c
+-c
+-c       Copy y into  w(16*m+71 : 16*m+n+70).
+-c
+-        do k = 1,n
+-          w(16*m+70+k) = y(k)
+-        enddo ! k
+-c
+-c
+-c       Fourier transform  w(16*m+71 : 16*m+n+70).
+-c
+-        call zfftf(n,w(16*m+70+1),w(4+m+n))
+-c
+-c
+-c       Permute  w(16*m+71 : 16*m+n+70)  to obtain y.
+-c
+-        call idz_permute(n,w(3+m),w(16*m+70+1),y)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_sfrm(l,m,n,w,x,y)
+-c
+-c       transforms x into y via a composition
+-c       of Rokhlin's random transform, random subselection, and an FFT.
+-c       In contrast to routine idz_frm, the present routine works best
+-c       when the length l of the transformed vector is known a priori.
+-c
+-c       input:
+-c       l -- length of y; l must be less than or equal to n
+-c       m -- length of x
+-c       n -- greatest integer expressible as a positive integer power
+-c            of 2 that is less than or equal to m, as obtained
+-c            from the routine idz_frmi
+-c       w -- initialization array constructed by routine idz_sfrmi
+-c       x -- vector to be transformed
+-c
+-c       output:
+-c       y -- transform of x
+-c
+-c       _N.B._: l must be less than or equal to n.
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,iw,n,l
+-        complex*16 w(21*m+70),x(m),y(l)
+-c
+-c
+-c       Apply Rokhlin's random transformation to x, obtaining
+-c       w(19*m+71 : 20*m+70).
+-c
+-        iw = w(4+m+l)
+-        call idz_random_transf(x,w(19*m+70+1),w(iw))
+-c
+-c
+-c       Subselect from  w(19*m+71 : 20*m+70)  to obtain
+-c       w(20*m+71 : 20*m+n+70).
+-c
+-        call idz_subselect(n,w(4),m,w(19*m+70+1),w(20*m+70+1))
+-c
+-c
+-c       Fourier transform  w(20*m+71 : 20*m+n+70).
+-c
+-        call idz_sfft(l,w(4+m),n,w(5+m+l),w(20*m+70+1))
+-c
+-c
+-c       Copy the desired entries from  w(20*m+71 : 20*m+n+70)
+-c       to y.
+-c
+-        call idz_subselect(l,w(4+m),n,w(20*m+70+1),y)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_permute(n,ind,x,y)
+-c
+-c       copy the entries of x into y, rearranged according
+-c       to the permutation specified by ind.
+-c
+-c       input:
+-c       n -- length of ind, x, and y
+-c       ind -- permutation of n objects
+-c       x -- vector to be permuted
+-c
+-c       output:
+-c       y -- permutation of x
+-c
+-        implicit none
+-        integer n,ind(n),k
+-        complex*16 x(n),y(n)
+-c
+-c
+-        do k = 1,n
+-          y(k) = x(ind(k))
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_subselect(n,ind,m,x,y)
+-c
+-c       copies into y the entries of x indicated by ind.
+-c
+-c       input:
+-c       n -- number of entries of x to copy into y
+-c       ind -- indices of the entries in x to copy into y
+-c       m -- length of x
+-c       x -- vector whose entries are to be copied
+-c
+-c       output:
+-c       y -- collection of entries of x specified by ind
+-c
+-        implicit none
+-        integer n,ind(n),m,k
+-        complex*16 x(m),y(n)
+-c
+-c
+-        do k = 1,n
+-          y(k) = x(ind(k))
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_frmi(m,n,w)
+-c
+-c       initializes data for the routine idz_frm.
+-c
+-c       input:
+-c       m -- length of the vector to be transformed
+-c
+-c       output:
+-c       n -- greatest integer expressible as a positive integer power
+-c            of 2 that is less than or equal to m
+-c       w -- initialization array to be used by routine idz_frm
+-c
+-c
+-c       glossary for the fully initialized w:
+-c
+-c       w(1) = m
+-c       w(2) = n
+-c       w(3:2+m) stores a permutation of m objects
+-c       w(3+m:2+m+n) stores a permutation of n objects
+-c       w(3+m+n) = address in w of the initialization array
+-c                  for idz_random_transf
+-c       w(4+m+n:int(w(3+m+n))-1) stores the initialization array
+-c                                for zfft
+-c       w(int(w(3+m+n)):16*m+70) stores the initialization array
+-c                                for idz_random_transf
+-c
+-c
+-c       _N.B._: n is an output of the present routine;
+-c               this routine changes n.
+-c
+-c
+-        implicit none
+-        integer m,n,l,nsteps,keep,lw,ia
+-        complex*16 w(17*m+70)
+-c
+-c
+-c       Find the greatest integer less than or equal to m
+-c       which is a power of two.
+-c
+-        call idz_poweroftwo(m,l,n)
+-c
+-c
+-c       Store m and n in w.
+-c
+-        w(1) = m
+-        w(2) = n
+-c
+-c
+-c       Store random permutations of m and n objects in w.
+-c
+-        call id_randperm(m,w(3))
+-        call id_randperm(n,w(3+m))
+-c
+-c
+-c       Store the address within w of the idz_random_transf_init
+-c       initialization data.
+-c
+-        ia = 4+m+n+2*n+15
+-        w(3+m+n) = ia
+-c
+-c
+-c       Store the initialization data for zfft in w.
+-c
+-        call zffti(n,w(4+m+n))
+-c
+-c
+-c       Store the initialization data for idz_random_transf_init in w.
+-c
+-        nsteps = 3
+-        call idz_random_transf_init(nsteps,m,w(ia),keep)
+-c
+-c
+-c       Calculate the total number of elements used in w.
+-c
+-        lw = 3+m+n+2*n+15 + 3*nsteps*m+2*m+m/4+50
+-c
+-        if(16*m+70 .lt. lw) then
+-          call prinf('lw = *',lw,1)
+-          call prinf('16m+70 = *',16*m+70,1)
+-          stop
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_sfrmi(l,m,n,w)
+-c
+-c       initializes data for the routine idz_sfrm.
+-c
+-c       input:
+-c       l -- length of the transformed (output) vector
+-c       m -- length of the vector to be transformed
+-c
+-c       output:
+-c       n -- greatest integer expressible as a positive integer power
+-c            of 2 that is less than or equal to m
+-c       w -- initialization array to be used by routine idz_sfrm
+-c
+-c
+-c       glossary for the fully initialized w:
+-c
+-c       w(1) = m
+-c       w(2) = n
+-c       w(3) is unused
+-c       w(4:3+m) stores a permutation of m objects
+-c       w(4+m:3+m+l) stores the indices of the l outputs which idz_sfft
+-c                    calculates
+-c       w(4+m+l) = address in w of the initialization array
+-c                  for idz_random_transf
+-c       w(5+m+l:int(w(4+m+l))-1) stores the initialization array
+-c                                for idz_sfft
+-c       w(int(w(4+m+l)):19*m+70) stores the initialization array
+-c                                for idz_random_transf
+-c
+-c
+-c       _N.B._: n is an output of the present routine;
+-c               this routine changes n.
+-c
+-c
+-        implicit none
+-        integer l,m,n,idummy,nsteps,keep,lw,ia
+-        complex*16 w(21*m+70)
+-c
+-c
+-c       Find the greatest integer less than or equal to m
+-c       which is a power of two.
+-c
+-        call idz_poweroftwo(m,idummy,n)
+-c
+-c
+-c       Store m and n in w.
+-c
+-        w(1) = m
+-        w(2) = n
+-        w(3) = 0
+-c
+-c
+-c       Store random permutations of m and n objects in w.
+-c
+-        call id_randperm(m,w(4))
+-        call id_randperm(n,w(4+m))
+-c
+-c
+-c       Store the address within w of the idz_random_transf_init
+-c       initialization data.
+-c
+-        ia = 5+m+l+2*l+15+3*n
+-        w(4+m+l) = ia
+-c
+-c
+-c       Store the initialization data for idz_sfft in w.
+-c
+-        call idz_sffti(l,w(4+m),n,w(5+m+l))
+-c
+-c
+-c       Store the initialization data for idz_random_transf_init in w.
+-c
+-        nsteps = 3
+-        call idz_random_transf_init(nsteps,m,w(ia),keep)
+-c
+-c
+-c       Calculate the total number of elements used in w.
+-c
+-        lw = 4+m+l+2*l+15+3*n + 3*nsteps*m+2*m+m/4+50
+-c
+-        if(19*m+70 .lt. lw) then
+-          call prinf('lw = *',lw,1)
+-          call prinf('19m+70 = *',19*m+70,1)
+-          stop
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_poweroftwo(m,l,n)
+-c
+-c       computes l = floor(log_2(m)) and n = 2**l.
+-c
+-c       input:
+-c       m -- integer whose log_2 is to be taken
+-c
+-c       output:
+-c       l -- floor(log_2(m))
+-c       n -- 2**l
+-c
+-        implicit none
+-        integer l,m,n
+-c
+-c
+-        l = 0
+-        n = 1
+-c
+- 1000   continue
+-          l = l+1
+-          n = n*2
+-        if(n .le. m) goto 1000
+-c
+-        l = l-1
+-        n = n/2
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idz_house.f b/scipy/linalg/src/id_dist/src/idz_house.f
+deleted file mode 100644
+index 93db06e6d..000000000
+--- a/scipy/linalg/src/id_dist/src/idz_house.f
++++ /dev/null
+@@ -1,298 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idz_house calculates the vector and scalar
+-c       needed to apply the Householder transformation reflecting
+-c       a given vector into its first component.
+-c
+-c       routine idz_houseapp applies a Householder matrix to a vector.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idz_houseapp(n,vn,u,ifrescal,scal,v)
+-c
+-c       applies the Householder matrix
+-c       identity_matrix - scal * vn * adjoint(vn)
+-c       to the vector u, yielding the vector v;
+-c
+-c       scal = 2/(1 + |vn(2)|^2 + ... + |vn(n)|^2)
+-c       when vn(2), ..., vn(n) don't all vanish;
+-c
+-c       scal = 0
+-c       when vn(2), ..., vn(n) do all vanish
+-c       (including when n = 1).
+-c
+-c       input:
+-c       n -- size of vn, u, and v, though the indexing on vn goes
+-c            from 2 to n
+-c       vn -- components 2 to n of the Householder vector vn;
+-c             vn(1) is assumed to be 1
+-c       u -- vector to be transformed
+-c       ifrescal -- set to 1 to recompute scal from vn(2), ..., vn(n);
+-c                   set to 0 to use scal as input
+-c       scal -- see the entry for ifrescal in the decription
+-c               of the input
+-c
+-c       output:
+-c       scal -- see the entry for ifrescal in the decription
+-c               of the input
+-c       v -- result of applying the Householder matrix to u;
+-c            it's O.K. to have v be the same as u
+-c            in order to apply the matrix to the vector in place
+-c
+-c       reference:
+-c       Golub and Van Loan, "Matrix Computations," 3rd edition,
+-c            Johns Hopkins University Press, 1996, Chapter 5.
+-c
+-        implicit none
+-        save
+-        integer n,k,ifrescal
+-        real*8 scal,sum
+-        complex*16 vn(2:*),u(n),v(n),fact
+-c
+-c
+-c       Get out of this routine if n = 1.
+-c
+-        if(n .eq. 1) then
+-          v(1) = u(1)
+-          return
+-        endif
+-c
+-c
+-        if(ifrescal .eq. 1) then
+-c
+-c
+-c         Calculate |vn(2)|^2 + ... + |vn(n)|^2.
+-c
+-          sum = 0
+-          do k = 2,n
+-            sum = sum+vn(k)*conjg(vn(k))
+-          enddo ! k
+-c
+-c
+-c         Calculate scal.
+-c
+-          if(sum .eq. 0) scal = 0
+-          if(sum .ne. 0) scal = 2/(1+sum)
+-c
+-c
+-        endif
+-c
+-c
+-c       Calculate fact = scal * adjoint(vn) * u.
+-c
+-        fact = u(1)
+-c
+-        do k = 2,n
+-          fact = fact+conjg(vn(k))*u(k)
+-        enddo ! k
+-c
+-        fact = fact*scal
+-c
+-c
+-c       Subtract fact*vn from u, yielding v.
+-c
+-        v(1) = u(1) - fact
+-c
+-        do k = 2,n
+-          v(k) = u(k) - fact*vn(k)
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_house(n,x,css,vn,scal)
+-c
+-c       constructs the vector vn with vn(1) = 1,
+-c       and the scalar scal, such that the obviously self-adjoint
+-c       H := identity_matrix - scal * vn * adjoint(vn) is unitary,
+-c       the absolute value of the first entry of Hx
+-c       is the root-sum-square of the entries of x,
+-c       and all other entries of Hx are zero
+-c       (H is the Householder matrix corresponding to x).
+-c
+-c       input:
+-c       n -- size of x and vn, though the indexing on vn goes
+-c            from 2 to n
+-c       x -- vector to reflect into its first component
+-c
+-c       output:
+-c       css -- root-sum-square of the entries of x * the phase of x(1)
+-c       vn -- entries 2 to n of the Householder vector vn;
+-c             vn(1) is assumed to be 1
+-c       scal -- scalar multiplying vn * adjoint(vn);
+-c
+-c               scal = 2/(1 + |vn(2)|^2 + ... + |vn(n)|^2)
+-c               when vn(2), ..., vn(n) don't all vanish;
+-c
+-c               scal = 0
+-c               when vn(2), ..., vn(n) do all vanish
+-c               (including when n = 1)
+-c
+-c       reference:
+-c       Golub and Van Loan, "Matrix Computations," 3rd edition,
+-c            Johns Hopkins University Press, 1996, Chapter 5.
+-c
+-        implicit none
+-        save
+-        integer n,k
+-        real*8 scal,test,rss,sum
+-        complex*16 x(n),v1,vn(2:*),x1,phase,css
+-c
+-c
+-        x1 = x(1)
+-c
+-c
+-c       Get out of this routine if n = 1.
+-c
+-        if(n .eq. 1) then
+-          css = x1
+-          scal = 0
+-          return
+-        endif
+-c
+-c
+-c       Calculate |x(2)|^2 + ... |x(n)|^2
+-c       and the root-sum-square value of the entries in x.
+-c
+-c
+-        sum = 0
+-        do k = 2,n
+-          sum = sum+x(k)*conjg(x(k))
+-        enddo ! k
+-c
+-c
+-c       Get out of this routine if sum = 0;
+-c       flag this case as such by setting v(2), ..., v(n) all to 0.
+-c
+-        if(sum .eq. 0) then
+-c
+-          css = x1
+-          do k = 2,n
+-            vn(k) = 0
+-          enddo ! k
+-          scal = 0
+-c
+-          return
+-c
+-        endif
+-c
+-c
+-        rss = x1*conjg(x1) + sum
+-        rss = sqrt(rss)
+-c
+-c
+-c       Determine the first component v1
+-c       of the unnormalized Householder vector
+-c       v = x - phase(x1) * rss * (1 0 0 ... 0 0)^T.
+-c
+-        if(x1 .eq. 0) phase = 1
+-        if(x1 .ne. 0) phase = x1/abs(x1)
+-        test = conjg(phase) * x1
+-        css = phase*rss
+-c
+-c       If test <= 0, then form x1-phase*rss directly,
+-c       since that expression cannot involve any cancellation.
+-c
+-        if(test .le. 0) v1 = x1-phase*rss
+-c
+-c       If test > 0, then use the fact that
+-c       x1-phase*rss = -phase*sum / ((phase)^* * x1 + rss),
+-c       in order to avoid potential cancellation.
+-c
+-        if(test .gt. 0) v1 = -phase*sum / (conjg(phase)*x1+rss)
+-c
+-c
+-c       Compute the vector vn and the scalar scal such that vn(1) = 1
+-c       in the Householder transformation
+-c       identity_matrix - scal * vn * adjoint(vn).
+-c
+-        do k = 2,n
+-          vn(k) = x(k)/v1
+-        enddo ! k
+-c
+-c       scal = 2
+-c            / ( |vn(1)|^2 + |vn(2)|^2 + ... + |vn(n)|^2 )
+-c
+-c            = 2
+-c            / ( 1 + |vn(2)|^2 + ... + |vn(n)|^2 )
+-c
+-c            = 2*|v(1)|^2
+-c            / ( |v(1)|^2 + |v(1)*vn(2)|^2 + ... + |v(1)*vn(n)|^2 )
+-c
+-c            = 2*|v(1)|^2
+-c            / ( |v(1)|^2 + (|v(2)|^2 + ... + |v(n)|^2) )
+-c
+-        scal = 2*v1*conjg(v1) / (v1*conjg(v1)+sum)
+-c
+-c
+-        rss = phase*rss
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_housemat(n,vn,scal,h)
+-c
+-c       fills h with the Householder matrix
+-c       identity_matrix - scal * vn * adjoint(vn).
+-c
+-c       input:
+-c       n -- size of vn and h, though the indexing of vn goes
+-c            from 2 to n
+-c       vn -- entries 2 to n of the vector vn;
+-c             vn(1) is assumed to be 1
+-c       scal -- scalar multiplying vn * adjoint(vn)
+-c
+-c       output:
+-c       h -- identity_matrix - scal * vn * adjoint(vn)
+-c
+-        implicit none
+-        save
+-        integer n,j,k
+-        real*8 scal
+-        complex*16 vn(2:*),h(n,n),factor1,factor2
+-c
+-c
+-c       Fill h with the identity matrix.
+-c
+-        do j = 1,n
+-          do k = 1,n
+-c
+-            if(j .eq. k) h(k,j) = 1
+-            if(j .ne. k) h(k,j) = 0
+-c
+-          enddo ! k
+-        enddo ! j
+-c
+-c
+-c       Subtract from h the matrix scal*vn*adjoint(vn).
+-c
+-        do j = 1,n
+-          do k = 1,n
+-c
+-            if(j .eq. 1) factor1 = 1
+-            if(j .ne. 1) factor1 = vn(j)
+-c
+-            if(k .eq. 1) factor2 = 1
+-            if(k .ne. 1) factor2 = conjg(vn(k))
+-c
+-            h(k,j) = h(k,j) - scal*factor1*factor2
+-c
+-          enddo ! k
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idz_id.f b/scipy/linalg/src/id_dist/src/idz_id.f
+deleted file mode 100644
+index 7a80243ff..000000000
+--- a/scipy/linalg/src/id_dist/src/idz_id.f
++++ /dev/null
+@@ -1,566 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzp_id computes the ID of a matrix,
+-c       to a specified precision.
+-c
+-c       routine idzr_id computes the ID of a matrix,
+-c       to a specified rank.
+-c
+-c       routine idz_reconid reconstructs a matrix from its ID.
+-c
+-c       routine idz_copycols collects together selected columns
+-c       of a matrix.
+-c
+-c       routine idz_getcols collects together selected columns
+-c       of a matrix specified by a routine for applying the matrix
+-c       to arbitrary vectors.
+-c
+-c       routine idz_reconint constructs p in the ID a = b p,
+-c       where the columns of b are a subset of the columns of a,
+-c       and p is the projection coefficient matrix,
+-c       given list, krank, and proj output by routines idzr_id
+-c       or idzp_id.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idzp_id(eps,m,n,a,krank,list,rnorms)
+-c
+-c       computes the ID of a, i.e., lists in list the indices
+-c       of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                        krank
+-c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
+-c                         l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon dimensioned epsilon(m,n-krank)
+-c       such that the greatest singular value of epsilon
+-c       <= the greatest singular value of a * eps.
+-c       The present routine stores the krank x (n-krank) matrix proj
+-c       in the memory initially occupied by a.
+-c
+-c       input:
+-c       eps -- relative precision of the resulting ID
+-c       m -- first dimension of a
+-c       n -- second dimension of a, as well as the dimension required
+-c            of list
+-c       a -- matrix to be ID'd
+-c
+-c       output:
+-c       a -- the first krank*(n-krank) elements of a constitute
+-c            the krank x (n-krank) interpolation matrix proj
+-c       krank -- numerical rank
+-c       list -- list of the indices of the krank columns of a
+-c               through which the other columns of a are expressed;
+-c               also, list describes the permutation of proj
+-c               required to reconstruct a as indicated in (*) above
+-c       rnorms -- absolute values of the entries on the diagonal
+-c                 of the triangular matrix used to compute the ID
+-c                 (these may be used to check the stability of the ID)
+-c
+-c       _N.B._: This routine changes a.
+-c
+-c       reference:
+-c       Cheng, Gimbutas, Martinsson, Rokhlin, "On the compression of
+-c            low-rank matrices," SIAM Journal on Scientific Computing,
+-c            26 (4): 1389-1404, 2005.
+-c
+-        implicit none
+-        integer m,n,krank,k,list(n),iswap
+-        real*8 eps,rnorms(n)
+-        complex*16 a(m,n)
+-c
+-c
+-c       QR decompose a.
+-c
+-        call idzp_qrpiv(eps,m,n,a,krank,list,rnorms)
+-c
+-c
+-c       Build the list of columns chosen in a
+-c       by multiplying together the permutations in list,
+-c       with the permutation swapping 1 and list(1) taken rightmost
+-c       in the product, that swapping 2 and list(2) taken next
+-c       rightmost, ..., that swapping krank and list(krank) taken
+-c       leftmost.
+-c
+-        do k = 1,n
+-          rnorms(k) = k
+-        enddo ! k
+-c
+-        if(krank .gt. 0) then
+-          do k = 1,krank
+-c
+-c           Swap rnorms(k) and rnorms(list(k)).
+-c
+-            iswap = rnorms(k)
+-            rnorms(k) = rnorms(list(k))
+-            rnorms(list(k)) = iswap
+-c
+-          enddo ! k
+-        endif
+-c
+-        do k = 1,n
+-          list(k) = rnorms(k)
+-        enddo ! k
+-c
+-c
+-c       Fill rnorms for the output.
+-c
+-        if(krank .gt. 0) then
+-c
+-          do k = 1,krank
+-            rnorms(k) = a(k,k)
+-          enddo ! k
+-c
+-        endif
+-c
+-c
+-c       Backsolve for proj, storing it at the beginning of a.
+-c
+-        if(krank .gt. 0) then
+-          call idz_lssolve(m,n,a,krank)
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzr_id(m,n,a,krank,list,rnorms)
+-c
+-c       computes the ID of a, i.e., lists in list the indices
+-c       of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                        krank
+-c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
+-c                         l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
+-c       whose norm is (hopefully) minimized by the pivoting procedure.
+-c       The present routine stores the krank x (n-krank) matrix proj
+-c       in the memory initially occupied by a.
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a, as well as the dimension required
+-c            of list
+-c       a -- matrix to be ID'd
+-c       krank -- desired rank of the output matrix
+-c                (please note that if krank > m or krank > n,
+-c                then the rank of the output matrix will be
+-c                less than krank)
+-c
+-c       output:
+-c       a -- the first krank*(n-krank) elements of a constitute
+-c            the krank x (n-krank) interpolation matrix proj
+-c       list -- list of the indices of the krank columns of a
+-c               through which the other columns of a are expressed;
+-c               also, list describes the permutation of proj
+-c               required to reconstruct a as indicated in (*) above
+-c       rnorms -- absolute values of the entries on the diagonal
+-c                 of the triangular matrix used to compute the ID
+-c                 (these may be used to check the stability of the ID)
+-c
+-c       _N.B._: This routine changes a.
+-c
+-c       reference:
+-c       Cheng, Gimbutas, Martinsson, Rokhlin, "On the compression of
+-c            low-rank matrices," SIAM Journal on Scientific Computing,
+-c            26 (4): 1389-1404, 2005.
+-c
+-        implicit none
+-        integer m,n,krank,j,k,list(n),iswap
+-        real*8 rnorms(n),ss
+-        complex*16 a(m,n)
+-c
+-c
+-c       QR decompose a.
+-c
+-        call idzr_qrpiv(m,n,a,krank,list,rnorms)
+-c
+-c
+-c       Build the list of columns chosen in a
+-c       by multiplying together the permutations in list,
+-c       with the permutation swapping 1 and list(1) taken rightmost
+-c       in the product, that swapping 2 and list(2) taken next
+-c       rightmost, ..., that swapping krank and list(krank) taken
+-c       leftmost.
+-c
+-        do k = 1,n
+-          rnorms(k) = k
+-        enddo ! k
+-c
+-        if(krank .gt. 0) then
+-          do k = 1,krank
+-c
+-c           Swap rnorms(k) and rnorms(list(k)).
+-c
+-            iswap = rnorms(k)
+-            rnorms(k) = rnorms(list(k))
+-            rnorms(list(k)) = iswap
+-c
+-          enddo ! k
+-        endif
+-c
+-        do k = 1,n
+-          list(k) = rnorms(k)
+-        enddo ! k
+-c
+-c
+-c       Fill rnorms for the output.
+-c
+-        ss = 0
+-c
+-        do k = 1,krank
+-          rnorms(k) = a(k,k)
+-          ss = ss + rnorms(k)**2
+-        enddo ! k
+-c
+-c
+-c       Backsolve for proj, storing it at the beginning of a.
+-c
+-        if(krank .gt. 0 .and. ss .gt. 0) then
+-          call idz_lssolve(m,n,a,krank)
+-        endif
+-c
+-        if(ss .eq. 0) then
+-c
+-          do k = 1,n
+-            do j = 1,m
+-c
+-              a(j,k) = 0
+-c
+-            enddo ! j
+-          enddo ! k
+-c
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_reconid(m,krank,col,n,list,proj,approx)
+-c
+-c       reconstructs the matrix that the routine idzp_id
+-c       or idzr_id has decomposed, using the columns col
+-c       of the reconstructed matrix whose indices are listed in list,
+-c       in addition to the interpolation matrix proj.
+-c
+-c       input:
+-c       m -- first dimension of cols and approx
+-c       krank -- first dimension of cols and proj; also,
+-c                n-krank is the second dimension of proj
+-c       col -- columns of the matrix to be reconstructed
+-c       n -- second dimension of approx; also,
+-c            n-krank is the second dimension of proj
+-c       list(k) -- index of col(1:m,k) in the reconstructed matrix
+-c                  when k <= krank; in general, list describes
+-c                  the permutation required for reconstruction
+-c                  via cols and proj
+-c       proj -- interpolation matrix
+-c
+-c       output:
+-c       approx -- reconstructed matrix
+-c
+-        implicit none
+-        integer m,n,krank,j,k,l,list(n)
+-        complex*16 col(m,krank),proj(krank,n-krank),approx(m,n)
+-c
+-c
+-        do j = 1,m
+-          do k = 1,n
+-c
+-            approx(j,list(k)) = 0
+-c
+-c           Add in the contributions due to the identity matrix.
+-c
+-            if(k .le. krank) then
+-              approx(j,list(k)) = approx(j,list(k)) + col(j,k)
+-            endif
+-c
+-c           Add in the contributions due to proj.
+-c
+-            if(k .gt. krank) then
+-              if(krank .gt. 0) then
+-c
+-                do l = 1,krank
+-                  approx(j,list(k)) = approx(j,list(k))
+-     1                              + col(j,l)*proj(l,k-krank)
+-                enddo ! l
+-c
+-              endif
+-            endif
+-c
+-          enddo ! k
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_lssolve(m,n,a,krank)
+-c
+-c       backsolves for proj satisfying R_11 proj ~ R_12,
+-c       where R_11 = a(1:krank,1:krank)
+-c       and R_12 = a(1:krank,krank+1:n).
+-c       This routine overwrites the beginning of a with proj.
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a; also,
+-c            n-krank is the second dimension of proj
+-c       a -- trapezoidal input matrix
+-c       krank -- first dimension of proj; also,
+-c                n-krank is the second dimension of proj
+-c
+-c       output:
+-c       a -- the first krank*(n-krank) elements of a constitute
+-c            the krank x (n-krank) matrix proj
+-c
+-        implicit none
+-        integer m,n,krank,j,k,l
+-        real*8 rnumer,rdenom
+-        complex*16 a(m,n),sum
+-c
+-c
+-c       Overwrite a(1:krank,krank+1:n) with proj.
+-c
+-        do k = 1,n-krank
+-          do j = krank,1,-1
+-c
+-            sum = 0
+-c
+-            do l = j+1,krank
+-              sum = sum+a(j,l)*a(l,krank+k)
+-            enddo ! l
+-c
+-            a(j,krank+k) = a(j,krank+k)-sum
+-c
+-c           Make sure that the entry in proj won't be too big;
+-c           set the entry to 0 when roundoff would make it too big
+-c           (in which case a(j,j) is so small that the contribution
+-c           from this entry in proj to the overall matrix approximation
+-c           is supposed to be negligible).
+-c
+-            rnumer = a(j,krank+k)*conjg(a(j,krank+k))
+-            rdenom = a(j,j)*conjg(a(j,j))
+-c
+-            if(rnumer .lt. 2**30*rdenom) then
+-              a(j,krank+k) = a(j,krank+k)/a(j,j)
+-            else
+-              a(j,krank+k) = 0
+-            endif
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-c       Move proj from a(1:krank,krank+1:n) to the beginning of a.
+-c
+-        call idz_moverup(m,n,krank,a)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_moverup(m,n,krank,a)
+-c
+-c       moves the krank x (n-krank) matrix in a(1:krank,krank+1:n),
+-c       where a is initially dimensioned m x n, to the beginning of a.
+-c       (This is not the most natural way to code the move,
+-c       but one of my usually well-behaved compilers chokes
+-c       on more natural ways.)
+-c
+-c       input:
+-c       m -- initial first dimension of a
+-c       n -- initial second dimension of a
+-c       krank -- number of rows to move
+-c       a -- m x n matrix whose krank x (n-krank) block
+-c            a(1:krank,krank+1:n) is to be moved
+-c
+-c       output:
+-c       a -- array starting with the moved krank x (n-krank) block
+-c
+-        implicit none
+-        integer m,n,krank,j,k
+-        complex*16 a(m*n)
+-c
+-c
+-        do k = 1,n-krank
+-          do j = 1,krank
+-            a(j+krank*(k-1)) = a(j+m*(krank+k-1))
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,
+-     1                         col,x)
+-c
+-c       collects together the columns of the matrix a indexed by list
+-c       into the matrix col, where routine matvec applies a
+-c       to an arbitrary vector.
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       matvec -- routine which applies a to an arbitrary vector;
+-c                 this routine must have a calling sequence of the form
+-c
+-c                 matvec(m,x,n,y,p1,p2,p3,p4)
+-c
+-c                 where m is the length of x,
+-c                 x is the vector to which the matrix is to be applied,
+-c                 n is the length of y,
+-c                 y is the product of the matrix and x,
+-c                 and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvec
+-c       p2 -- parameter to be passed to routine matvec
+-c       p3 -- parameter to be passed to routine matvec
+-c       p4 -- parameter to be passed to routine matvec
+-c       krank -- number of columns to be extracted
+-c       list -- indices of the columns to be extracted
+-c
+-c       output:
+-c       col -- columns of a indexed by list
+-c
+-c       work:
+-c       x -- must be at least n complex*16 elements long
+-c
+-        implicit none
+-        integer m,n,krank,list(krank),j,k
+-        complex*16 col(m,krank),x(n),p1,p2,p3,p4
+-        external matvec
+-c
+-c
+-        do j = 1,krank
+-c
+-          do k = 1,n
+-            x(k) = 0
+-          enddo ! k
+-c
+-          x(list(j)) = 1
+-c
+-          call matvec(n,x,m,col(1,j),p1,p2,p3,p4)
+-c
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_reconint(n,list,krank,proj,p)
+-c
+-c       constructs p in the ID a = b p,
+-c       where the columns of b are a subset of the columns of a,
+-c       and p is the projection coefficient matrix,
+-c       given list, krank, and proj output
+-c       by routines idzp_id or idzr_id.
+-c
+-c       input:
+-c       n -- part of the second dimension of proj and p
+-c       list -- list of columns retained from the original matrix
+-c               in the ID
+-c       krank -- rank of the ID
+-c       proj -- matrix of projection coefficients in the ID
+-c
+-c       output:
+-c       p -- projection matrix in the ID
+-c
+-        implicit none
+-        integer n,krank,list(n),j,k
+-        complex*16 proj(krank,n-krank),p(krank,n)
+-c
+-c
+-        do k = 1,krank
+-          do j = 1,n
+-c
+-            if(j .le. krank) then
+-              if(j .eq. k) p(k,list(j)) = 1
+-              if(j .ne. k) p(k,list(j)) = 0
+-            endif
+-c
+-            if(j .gt. krank) then
+-              p(k,list(j)) = proj(k,j-krank)
+-            endif
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_copycols(m,n,a,krank,list,col)
+-c
+-c       collects together the columns of the matrix a indexed by list
+-c       into the matrix col.
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       a -- matrix whose columns are to be extracted
+-c       krank -- number of columns to be extracted
+-c       list -- indices of the columns to be extracted
+-c
+-c       output:
+-c       col -- columns of a indexed by list
+-c
+-        implicit none
+-        integer m,n,krank,list(krank),j,k
+-        complex*16 a(m,n),col(m,krank)
+-c
+-c
+-        do k = 1,krank
+-          do j = 1,m
+-c
+-            col(j,k) = a(j,list(k))
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idz_id2svd.f b/scipy/linalg/src/id_dist/src/idz_id2svd.f
+deleted file mode 100644
+index 55832e5d1..000000000
+--- a/scipy/linalg/src/id_dist/src/idz_id2svd.f
++++ /dev/null
+@@ -1,389 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idz_id2svd converts an approximation to a matrix
+-c       in the form of an ID to an approximation in the form of an SVD.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idz_id2svd(m,krank,b,n,list,proj,u,v,s,ier,w)
+-c
+-c       converts an approximation to a matrix in the form of an ID
+-c       to an approximation in the form of an SVD.
+-c
+-c       input:
+-c       m -- first dimension of b
+-c       krank -- rank of the ID
+-c       b -- columns of the original matrix in the ID
+-c       list -- list of columns chosen from the original matrix
+-c               in the ID
+-c       n -- length of list and part of the second dimension of proj
+-c       proj -- projection coefficients in the ID
+-c
+-c       output:
+-c       u -- left singular vectors
+-c       v -- right singular vectors
+-c       s -- singular values
+-c       ier -- 0 when the routine terminates successfully;
+-c              nonzero otherwise
+-c
+-c       work:
+-c       w -- must be at least (krank+1)*(m+3*n+10)+9*krank**2
+-c            complex*16 elements long
+-c
+-c       _N.B._: This routine destroys b.
+-c
+-        implicit none
+-        integer m,krank,n,list(n),iwork,lwork,ip,lp,it,lt,ir,lr,
+-     1          ir2,lr2,ir3,lr3,iind,lind,iindt,lindt,lw,ier
+-        real*8 s(krank)
+-        complex*16 b(m,krank),proj(krank,n-krank),u(m,krank),
+-     1             v(n,krank),w((krank+1)*(m+3*n+10)+9*krank**2)
+-c
+-c
+-c       Allocate memory for idz_id2svd0.
+-c
+-        lw = 0
+-c
+-        iwork = lw+1
+-        lwork = 8*krank**2+10*krank
+-        lw = lw+lwork
+-c
+-        ip = lw+1
+-        lp = krank*n
+-        lw = lw+lp
+-c
+-        it = lw+1
+-        lt = n*krank
+-        lw = lw+lt
+-c
+-        ir = lw+1
+-        lr = krank*n
+-        lw = lw+lr
+-c
+-        ir2 = lw+1
+-        lr2 = krank*m
+-        lw = lw+lr2
+-c
+-        ir3 = lw+1
+-        lr3 = krank*krank
+-        lw = lw+lr3
+-c
+-        iind = lw+1
+-        lind = n/4+1
+-        lw = lw+1
+-c
+-        iindt = lw+1
+-        lindt = m/4+1
+-        lw = lw+1
+-c
+-c
+-        call idz_id2svd0(m,krank,b,n,list,proj,u,v,s,ier,
+-     1                   w(iwork),w(ip),w(it),w(ir),w(ir2),w(ir3),
+-     2                   w(iind),w(iindt))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_id2svd0(m,krank,b,n,list,proj,u,v,s,ier,
+-     1                         work,p,t,r,r2,r3,ind,indt)
+-c
+-c       routine idz_id2svd serves as a memory wrapper
+-c       for the present routine (please see routine idz_id2svd
+-c       for further documentation).
+-c
+-        implicit none
+-c
+-        character*1 jobz
+-        integer m,n,krank,list(n),ind(n),indt(m),ifadjoint,
+-     1          lwork,ldu,ldvt,ldr,info,j,k,ier
+-        real*8 s(krank)
+-        complex*16 b(m,krank),proj(krank,n-krank),p(krank,n),
+-     1             r(krank,n),r2(krank,m),t(n,krank),r3(krank,krank),
+-     2             u(m,krank),v(n,krank),work(8*krank**2+10*krank)
+-c
+-c
+-c
+-        ier = 0
+-c
+-c
+-c
+-c       Construct the projection matrix p from the ID.
+-c
+-        call idz_reconint(n,list,krank,proj,p)
+-c
+-c
+-c
+-c       Compute a pivoted QR decomposition of b.
+-c
+-        call idzr_qrpiv(m,krank,b,krank,ind,r)
+-c
+-c
+-c       Extract r from the QR decomposition.
+-c
+-        call idz_rinqr(m,krank,b,krank,r)
+-c
+-c
+-c       Rearrange r according to ind.
+-c
+-        call idz_rearr(krank,ind,krank,krank,r)
+-c
+-c
+-c
+-c       Take the adjoint of p to obtain t.
+-c
+-        call idz_matadj(krank,n,p,t)
+-c
+-c
+-c       Compute a pivoted QR decomposition of t.
+-c
+-        call idzr_qrpiv(n,krank,t,krank,indt,r2)
+-c
+-c
+-c       Extract r2 from the QR decomposition.
+-c
+-        call idz_rinqr(n,krank,t,krank,r2)
+-c
+-c
+-c       Rearrange r2 according to indt.
+-c
+-        call idz_rearr(krank,indt,krank,krank,r2)
+-c
+-c
+-c
+-c       Multiply r and r2^* to obtain r3.
+-c
+-        call idz_matmulta(krank,krank,r,krank,r2,r3)
+-c
+-c
+-c
+-c       Use LAPACK to SVD r3.
+-c
+-        jobz = 'S'
+-        ldr = krank
+-        lwork = 8*krank**2+10*krank
+-     1        - (krank**2+2*krank+3*krank**2+4*krank)
+-        ldu = krank
+-        ldvt = krank
+-c
+-        call zgesdd(jobz,krank,krank,r3,ldr,s,work,ldu,r,ldvt,
+-     1              work(krank**2+2*krank+3*krank**2+4*krank+1),lwork,
+-     2              work(krank**2+2*krank+1),work(krank**2+1),info)
+-c
+-        if(info .ne. 0) then
+-          ier = info
+-          return
+-        endif
+-c
+-c
+-c
+-c       Multiply the u from r3 from the left by the q from b
+-c       to obtain the u for a.
+-c
+-        do k = 1,krank
+-c
+-          do j = 1,krank
+-            u(j,k) = work(j+krank*(k-1))
+-          enddo ! j
+-c
+-          do j = krank+1,m
+-            u(j,k) = 0
+-          enddo ! j
+-c
+-        enddo ! k
+-c
+-        ifadjoint = 0
+-        call idz_qmatmat(ifadjoint,m,krank,b,krank,krank,u,r2)
+-c
+-c
+-c
+-c       Take the adjoint of r to obtain r2.
+-c
+-        call idz_matadj(krank,krank,r,r2)
+-c
+-c
+-c       Multiply the v from r3 from the left by the q from p^*
+-c       to obtain the v for a.
+-c
+-        do k = 1,krank
+-c
+-          do j = 1,krank
+-            v(j,k) = r2(j,k)
+-          enddo ! j
+-c
+-          do j = krank+1,n
+-            v(j,k) = 0
+-          enddo ! j
+-c
+-        enddo ! k
+-c
+-        ifadjoint = 0
+-        call idz_qmatmat(ifadjoint,n,krank,t,krank,krank,v,r2)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_matadj(m,n,a,aa)
+-c
+-c       Takes the adjoint of a to obtain aa.
+-c
+-c       input:
+-c       m -- first dimension of a, and second dimension of aa
+-c       n -- second dimension of a, and first dimension of aa
+-c       a -- matrix whose adjoint is to be taken
+-c
+-c       output:
+-c       aa -- adjoint of a
+-c
+-        implicit none
+-        integer m,n,j,k
+-        complex*16 a(m,n),aa(n,m)
+-c
+-c
+-        do k = 1,n
+-          do j = 1,m
+-            aa(k,j) = conjg(a(j,k))
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_matmulta(l,m,a,n,b,c)
+-c
+-c       multiplies a and b^* to obtain c.
+-c
+-c       input:
+-c       l -- first dimension of a and c
+-c       m -- second dimension of a and b
+-c       a -- leftmost matrix in the product c = a b^*
+-c       n -- first dimension of b and second dimension of c
+-c       b -- rightmost matrix in the product c = a b^*
+-c
+-c       output:
+-c       c -- product of a and b^*
+-c
+-        implicit none
+-        integer l,m,n,i,j,k
+-        complex*16 a(l,m),b(n,m),c(l,n),sum
+-c
+-c
+-        do i = 1,l
+-          do k = 1,n
+-c
+-            sum = 0
+-c
+-            do j = 1,m
+-              sum = sum+a(i,j)*conjg(b(k,j))
+-            enddo ! j
+-c
+-            c(i,k) = sum
+-c
+-          enddo ! k
+-        enddo ! i
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_rearr(krank,ind,m,n,a)
+-c
+-c       rearranges a according to ind obtained
+-c       from routines idzr_qrpiv or idzp_qrpiv,
+-c       assuming that a = q r, where q and r are from idzr_qrpiv
+-c       or idzp_qrpiv.
+-c
+-c       input:
+-c       krank -- rank obtained from routine idzp_qrpiv,
+-c                or provided to routine idzr_qrpiv
+-c       ind -- indexing array obtained from routine idzr_qrpiv
+-c              or idzp_qrpiv
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       a -- matrix to be rearranged
+-c
+-c       output:
+-c       a -- rearranged matrix
+-c
+-        implicit none
+-        integer k,krank,m,n,j,ind(krank)
+-        complex*16 cswap,a(m,n)
+-c
+-c
+-        do k = krank,1,-1
+-          do j = 1,m
+-c
+-            cswap = a(j,k)
+-            a(j,k) = a(j,ind(k))
+-            a(j,ind(k)) = cswap
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_rinqr(m,n,a,krank,r)
+-c
+-c       extracts R in the QR decomposition specified by the output a
+-c       of the routine idzr_qrpiv or idzp_qrpiv.
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a and r
+-c       a -- output of routine idzr_qrpiv or idzp_qrpiv
+-c       krank -- rank output by routine idzp_qrpiv (or specified
+-c                to routine idzr_qrpiv)
+-c
+-c       output:
+-c       r -- triangular factor in the QR decomposition specified
+-c            by the output a of the routine idzr_qrpiv or idzp_qrpiv
+-c
+-        implicit none
+-        integer m,n,j,k,krank
+-        complex*16 a(m,n),r(krank,n)
+-c
+-c
+-c       Copy a into r and zero out the appropriate
+-c       Householder vectors that are stored in one triangle of a.
+-c
+-        do k = 1,n
+-          do j = 1,krank
+-            r(j,k) = a(j,k)
+-          enddo ! j
+-        enddo ! k
+-c
+-        do k = 1,n
+-          if(k .lt. krank) then
+-            do j = k+1,krank
+-              r(j,k) = 0
+-            enddo ! j
+-          endif
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idz_qrpiv.f b/scipy/linalg/src/id_dist/src/idz_qrpiv.f
+deleted file mode 100644
+index 3e7bcaf99..000000000
+--- a/scipy/linalg/src/id_dist/src/idz_qrpiv.f
++++ /dev/null
+@@ -1,898 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzp_qrpiv computes the pivoted QR decomposition
+-c       of a matrix via Householder transformations,
+-c       stopping at a specified precision of the decomposition.
+-c
+-c       routine idzr_qrpiv computes the pivoted QR decomposition
+-c       of a matrix via Householder transformations,
+-c       stopping at a specified rank of the decomposition.
+-c
+-c       routine idz_qmatvec applies to a single vector
+-c       the Q matrix (or its adjoint) in the QR decomposition
+-c       of a matrix, as described by the output of idzp_qrpiv or
+-c       idzr_qrpiv. If you're concerned about efficiency and want
+-c       to apply Q (or its adjoint) to multiple vectors,
+-c       use idz_qmatmat instead.
+-c
+-c       routine idz_qmatmat applies
+-c       to multiple vectors collected together
+-c       as a matrix the Q matrix (or its adjoint)
+-c       in the QR decomposition of a matrix, as described
+-c       by the output of idzp_qrpiv. If you don't want to provide
+-c       a work array and want to apply Q (or its adjoint)
+-c       to a single vector, use idz_qmatvec instead.
+-c
+-c       routine idz_qinqr reconstructs the Q matrix
+-c       in a QR decomposition from the data generated by idzp_qrpiv
+-c       or idzr_qrpiv.
+-c
+-c       routine idz_permmult multiplies together a bunch
+-c       of permutations.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idz_permmult(m,ind,n,indprod)
+-c
+-c       multiplies together the series of permutations in ind.
+-c
+-c       input:
+-c       m -- length of ind
+-c       ind(k) -- number of the slot with which to swap
+-c                 the k^th slot
+-c       n -- length of indprod and indprodinv
+-c
+-c       output:
+-c       indprod -- product of the permutations in ind,
+-c                  with the permutation swapping 1 and ind(1)
+-c                  taken leftmost in the product,
+-c                  that swapping 2 and ind(2) taken next leftmost,
+-c                  ..., that swapping krank and ind(krank)
+-c                  taken rightmost; indprod(k) is the number
+-c                  of the slot with which to swap the k^th slot
+-c                  in the product permutation
+-c
+-        implicit none
+-        integer m,n,ind(m),indprod(n),k,iswap
+-c
+-c
+-        do k = 1,n
+-          indprod(k) = k
+-        enddo ! k
+-c
+-        do k = m,1,-1
+-c
+-c         Swap indprod(k) and indprod(ind(k)).
+-c
+-          iswap = indprod(k)
+-          indprod(k) = indprod(ind(k))
+-          indprod(ind(k)) = iswap
+-c
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_qinqr(m,n,a,krank,q)
+-c
+-c       constructs the matrix q from idzp_qrpiv or idzr_qrpiv
+-c       (see the routine idzp_qrpiv or idzr_qrpiv
+-c       for more information).
+-c
+-c       input:
+-c       m -- first dimension of a; also, right now, q is m x m
+-c       n -- second dimension of a
+-c       a -- matrix output by idzp_qrpiv or idzr_qrpiv
+-c            (and denoted the same there)
+-c       krank -- numerical rank output by idzp_qrpiv or idzr_qrpiv
+-c                (and denoted the same there)
+-c
+-c       output:
+-c       q -- unitary matrix implicitly specified by the data in a
+-c            from idzp_qrpiv or idzr_qrpiv
+-c
+-c       Note:
+-c       Right now, this routine simply multiplies
+-c       one after another the krank Householder matrices
+-c       in the full QR decomposition of a,
+-c       in order to obtain the complete m x m Q factor in the QR.
+-c       This routine should instead use the following
+-c       (more elaborate but more efficient) scheme
+-c       to construct a q dimensioned q(krank,m); this scheme
+-c       was introduced by Robert Schreiber and Charles Van Loan
+-c       in "A Storage-Efficient _WY_ Representation
+-c       for Products of Householder Transformations,"
+-c       _SIAM Journal on Scientific and Statistical Computing_,
+-c       Vol. 10, No. 1, pp. 53-57, January, 1989:
+-c
+-c       Theorem 1. Suppose that Q = _1_ + YTY^* is
+-c       an m x m unitary matrix,
+-c       where Y is an m x k matrix
+-c       and T is a k x k upper triangular matrix.
+-c       Suppose also that P = _1_ - 2 v v^* is
+-c       a Householder matrix and Q_+ = QP,
+-c       where v is an m x 1 real vector,
+-c       normalized so that v^* v = 1.
+-c       Then, Q_+ = _1_ + Y_+ T_+ Y_+^*,
+-c       where Y_+ = (Y v) is the m x (k+1) matrix
+-c       formed by adjoining v to the right of Y,
+-c                 ( T   z )
+-c       and T_+ = (       ) is
+-c                 ( 0  -2 )
+-c       the (k+1) x (k+1) upper triangular matrix
+-c       formed by adjoining z to the right of T
+-c       and the vector (0 ... 0 -2) with k zeroes below (T z),
+-c       where z = -2 T Y^* v.
+-c
+-c       Now, suppose that A is a (rank-deficient) matrix
+-c       whose complete QR decomposition has
+-c       the blockwise partioned form
+-c           ( Q_11 Q_12 ) ( R_11 R_12 )   ( Q_11 )
+-c       A = (           ) (           ) = (      ) (R_11 R_12).
+-c           ( Q_21 Q_22 ) (  0    0   )   ( Q_21 )
+-c       Then, the only blocks of the orthogonal factor
+-c       in the above QR decomposition of A that matter are
+-c                                                        ( Q_11 )
+-c       Q_11 and Q_21, _i.e._, only the block of columns (      )
+-c                                                        ( Q_21 )
+-c       interests us.
+-c       Suppose in addition that Q_11 is a k x k matrix,
+-c       Q_21 is an (m-k) x k matrix, and that
+-c       ( Q_11 Q_12 )
+-c       (           ) = _1_ + YTY^*, as in Theorem 1 above.
+-c       ( Q_21 Q_22 )
+-c       Then, Q_11 = _1_ + Y_1 T Y_1^*
+-c       and Q_21 = Y_2 T Y_1^*,
+-c       where Y_1 is the k x k matrix and Y_2 is the (m-k) x k matrix
+-c                   ( Y_1 )
+-c       so that Y = (     ).
+-c                   ( Y_2 )
+-c
+-c       So, you can calculate T and Y via the above recursions,
+-c       and then use these to compute the desired Q_11 and Q_21.
+-c
+-c
+-        implicit none
+-        integer m,n,krank,j,k,mm,ifrescal
+-        real*8 scal
+-        complex*16 a(m,n),q(m,m)
+-c
+-c
+-c       Zero all of the entries of q.
+-c
+-        do k = 1,m
+-          do j = 1,m
+-            q(j,k) = 0
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-c       Place 1's along the diagonal of q.
+-c
+-        do k = 1,m
+-          q(k,k) = 1
+-        enddo ! k
+-c
+-c
+-c       Apply the krank Householder transformations stored in a.
+-c
+-        do k = krank,1,-1
+-          do j = k,m
+-            mm = m-k+1
+-            ifrescal = 1
+-            if(k .lt. m) call idz_houseapp(mm,a(k+1,k),q(k,j),
+-     1                                     ifrescal,scal,q(k,j))
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_qmatvec(ifadjoint,m,n,a,krank,v)
+-c
+-c       applies to a single vector the Q matrix (or its adjoint)
+-c       which the routine idzp_qrpiv or idzr_qrpiv has stored
+-c       in a triangle of the matrix it produces (stored, incidentally,
+-c       as data for applying a bunch of Householder reflections).
+-c       Use the routine idz_qmatmat to apply the Q matrix
+-c       (or its adjoint)
+-c       to a bunch of vectors collected together as a matrix,
+-c       if you're concerned about efficiency.
+-c
+-c       input:
+-c       ifadjoint -- set to 0 for applying Q;
+-c                    set to 1 for applying the adjoint of Q
+-c       m -- first dimension of a and length of v
+-c       n -- second dimension of a
+-c       a -- data describing the qr decomposition of a matrix,
+-c            as produced by idzp_qrpiv or idzr_qrpiv
+-c       krank -- numerical rank
+-c       v -- vector to which Q (or its adjoint) is to be applied
+-c
+-c       output:
+-c       v -- vector to which Q (or its adjoint) has been applied
+-c
+-        implicit none
+-        save
+-        integer m,n,krank,k,ifrescal,mm,ifadjoint
+-        real*8 scal
+-        complex*16 a(m,n),v(m)
+-c
+-c
+-        ifrescal = 1
+-c
+-c
+-        if(ifadjoint .eq. 0) then
+-c
+-          do k = krank,1,-1
+-            mm = m-k+1
+-            if(k .lt. m) call idz_houseapp(mm,a(k+1,k),v(k),
+-     1                                     ifrescal,scal,v(k))
+-          enddo ! k
+-c
+-        endif
+-c
+-c
+-        if(ifadjoint .eq. 1) then
+-c
+-          do k = 1,krank
+-            mm = m-k+1
+-            if(k .lt. m) call idz_houseapp(mm,a(k+1,k),v(k),
+-     1                                     ifrescal,scal,v(k))
+-          enddo ! k
+-c
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_qmatmat(ifadjoint,m,n,a,krank,l,b,work)
+-c
+-c       applies to a bunch of vectors collected together as a matrix
+-c       the Q matrix (or its adjoint) which the routine idzp_qrpiv
+-c       or idzr_qrpiv has stored in a triangle of the matrix
+-c       it produces (stored, incidentally, as data
+-c       for applying a bunch of Householder reflections).
+-c       Use the routine idz_qmatvec to apply the Q matrix
+-c       (or its adjoint)
+-c       to a single vector, if you'd rather not provide a work array.
+-c
+-c       input:
+-c       ifadjoint -- set to 0 for applying Q;
+-c                    set to 1 for applying the adjoint of Q
+-c       m -- first dimension of both a and b
+-c       n -- second dimension of a
+-c       a -- data describing the qr decomposition of a matrix,
+-c            as produced by idzp_qrpiv or idzr_qrpiv
+-c       krank -- numerical rank
+-c       l -- second dimension of b
+-c       b -- matrix to which Q (or its adjoint) is to be applied
+-c
+-c       output:
+-c       b -- matrix to which Q (or its adjoint) has been applied
+-c
+-c       work:
+-c       work -- must be at least krank real*8 elements long
+-c
+-        implicit none
+-        save
+-        integer l,m,n,krank,j,k,ifrescal,mm,ifadjoint
+-        real*8 work(krank)
+-        complex*16 a(m,n),b(m,l)
+-c
+-c
+-        if(ifadjoint .eq. 0) then
+-c
+-c
+-c         Handle the first iteration, j = 1,
+-c         calculating all scals (ifrescal = 1).
+-c
+-          ifrescal = 1
+-c
+-          j = 1
+-c
+-          do k = krank,1,-1
+-            if(k .lt. m) then
+-              mm = m-k+1
+-              call idz_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
+-     1                          work(k),b(k,j))
+-            endif
+-          enddo ! k
+-c
+-c
+-          if(l .gt. 1) then
+-c
+-c           Handle the other iterations, j > 1,
+-c           using the scals just computed (ifrescal = 0).
+-c
+-            ifrescal = 0
+-c
+-            do j = 2,l
+-c
+-              do k = krank,1,-1
+-                if(k .lt. m) then
+-                  mm = m-k+1
+-                  call idz_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
+-     1                              work(k),b(k,j))
+-                endif
+-              enddo ! k
+-c
+-            enddo ! j
+-c
+-          endif ! j .gt. 1
+-c
+-c
+-        endif ! ifadjoint .eq. 0
+-c
+-c
+-        if(ifadjoint .eq. 1) then
+-c
+-c
+-c         Handle the first iteration, j = 1,
+-c         calculating all scals (ifrescal = 1).
+-c
+-          ifrescal = 1
+-c
+-          j = 1
+-c
+-          do k = 1,krank
+-            if(k .lt. m) then
+-              mm = m-k+1
+-              call idz_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
+-     1                          work(k),b(k,j))
+-            endif
+-          enddo ! k
+-c
+-c
+-          if(l .gt. 1) then
+-c
+-c           Handle the other iterations, j > 1,
+-c           using the scals just computed (ifrescal = 0).
+-c
+-            ifrescal = 0
+-c
+-            do j = 2,l
+-c
+-              do k = 1,krank
+-                if(k .lt. m) then
+-                  mm = m-k+1
+-                  call idz_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
+-     1                              work(k),b(k,j))
+-                endif
+-              enddo ! k
+-c
+-            enddo ! j
+-c
+-          endif ! j .gt. 1
+-c
+-c
+-        endif ! ifadjoint .eq. 1
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzp_qrpiv(eps,m,n,a,krank,ind,ss)
+-c
+-c       computes the pivoted QR decomposition
+-c       of the matrix input into a, using Householder transformations,
+-c       _i.e._, transforms the matrix a from its input value in
+-c       to the matrix out with entry
+-c
+-c                               m
+-c       out(j,indprod(k))  =  Sigma  q(l,j) * in(l,k),
+-c                              l=1
+-c
+-c       for all j = 1, ..., krank, and k = 1, ..., n,
+-c
+-c       where in = the a from before the routine runs,
+-c       out = the a from after the routine runs,
+-c       out(j,k) = 0 when j > k (so that out is triangular),
+-c       q(1:m,1), ..., q(1:m,krank) are orthonormal,
+-c       indprod is the product of the permutations given by ind,
+-c       (as computable via the routine permmult,
+-c       with the permutation swapping 1 and ind(1) taken leftmost
+-c       in the product, that swapping 2 and ind(2) taken next leftmost,
+-c       ..., that swapping krank and ind(krank) taken rightmost),
+-c       and with the matrix out satisfying
+-c
+-c                   krank
+-c       in(j,k)  =  Sigma  q(j,l) * out(l,indprod(k))  +  epsilon(j,k),
+-c                    l=1
+-c
+-c       for all j = 1, ..., m, and k = 1, ..., n,
+-c
+-c       for some matrix epsilon such that
+-c       the root-sum-square of the entries of epsilon
+-c       <= the root-sum-square of the entries of in * eps.
+-c       Well, technically, this routine outputs the Householder vectors
+-c       (or, rather, their second through last entries)
+-c       in the part of a that is supposed to get zeroed, that is,
+-c       in a(j,k) with m >= j > k >= 1.
+-c
+-c       input:
+-c       eps -- relative precision of the resulting QR decomposition
+-c       m -- first dimension of a and q
+-c       n -- second dimension of a
+-c       a -- matrix whose QR decomposition gets computed
+-c
+-c       output:
+-c       a -- triangular (R) factor in the QR decompositon
+-c            of the matrix input into the same storage locations,
+-c            with the Householder vectors stored in the part of a
+-c            that would otherwise consist entirely of zeroes, that is,
+-c            in a(j,k) with m >= j > k >= 1
+-c       krank -- numerical rank
+-c       ind(k) -- index of the k^th pivot vector;
+-c                 the following code segment will correctly rearrange
+-c                 the product b of q and the upper triangle of out
+-c                 so that b matches the input matrix in
+-c                 to relative precision eps:
+-c
+-c                 copy the non-rearranged product of q and out into b
+-c                 set k to krank
+-c                 [start of loop]
+-c                   swap b(1:m,k) and b(1:m,ind(k))
+-c                   decrement k by 1
+-c                 if k > 0, then go to [start of loop]
+-c
+-c       work:
+-c       ss -- must be at least n real*8 words long
+-c
+-c       _N.B._: This routine outputs the Householder vectors
+-c       (or, rather, their second through last entries)
+-c       in the part of a that is supposed to get zeroed, that is,
+-c       in a(j,k) with m >= j > k >= 1.
+-c
+-c       reference:
+-c       Golub and Van Loan, "Matrix Computations," 3rd edition,
+-c            Johns Hopkins University Press, 1996, Chapter 5.
+-c
+-        implicit none
+-        integer n,m,ind(n),krank,k,j,kpiv,mm,nupdate,ifrescal
+-        real*8 ss(n),eps,ssmax,scal,ssmaxin,rswap,feps
+-        complex*16 a(m,n),cswap
+-c
+-c
+-        feps = .1d-16
+-c
+-c
+-c       Compute the sum of squares of the entries in each column of a,
+-c       the maximum of all such sums, and find the first pivot
+-c       (column with the greatest such sum).
+-c
+-        ssmax = 0
+-        kpiv = 1
+-c
+-        do k = 1,n
+-c
+-          ss(k) = 0
+-          do j = 1,m
+-            ss(k) = ss(k)+a(j,k)*conjg(a(j,k))
+-          enddo ! j
+-c
+-          if(ss(k) .gt. ssmax) then
+-            ssmax = ss(k)
+-            kpiv = k
+-          endif
+-c
+-        enddo ! k
+-c
+-        ssmaxin = ssmax
+-c
+-        nupdate = 0
+-c
+-c
+-c       While ssmax > eps**2*ssmaxin, krank < m, and krank < n,
+-c       do the following block of code,
+-c       which ends at the statement labeled 2000.
+-c
+-        krank = 0
+- 1000   continue
+-c
+-        if(ssmax .le. eps**2*ssmaxin
+-     1   .or. krank .ge. m .or. krank .ge. n) goto 2000
+-        krank = krank+1
+-c
+-c
+-          mm = m-krank+1
+-c
+-c
+-c         Perform the pivoting.
+-c
+-          ind(krank) = kpiv
+-c
+-c         Swap a(1:m,krank) and a(1:m,kpiv).
+-c
+-          do j = 1,m
+-            cswap = a(j,krank)
+-            a(j,krank) = a(j,kpiv)
+-            a(j,kpiv) = cswap
+-          enddo ! j
+-c
+-c         Swap ss(krank) and ss(kpiv).
+-c
+-          rswap = ss(krank)
+-          ss(krank) = ss(kpiv)
+-          ss(kpiv) = rswap
+-c
+-c
+-          if(krank .lt. m) then
+-c
+-c
+-c           Compute the data for the Householder transformation
+-c           which will zero a(krank+1,krank), ..., a(m,krank)
+-c           when applied to a, replacing a(krank,krank)
+-c           with the first entry of the result of the application
+-c           of the Householder matrix to a(krank:m,krank),
+-c           and storing entries 2 to mm of the Householder vector
+-c           in a(krank+1,krank), ..., a(m,krank)
+-c           (which otherwise would get zeroed upon application
+-c           of the Householder transformation).
+-c
+-            call idz_house(mm,a(krank,krank),a(krank,krank),
+-     1                     a(krank+1,krank),scal)
+-            ifrescal = 0
+-c
+-c
+-c           Apply the Householder transformation
+-c           to the lower right submatrix of a
+-c           with upper leftmost entry at position (krank,krank+1).
+-c
+-            if(krank .lt. n) then
+-              do k = krank+1,n
+-                call idz_houseapp(mm,a(krank+1,krank),a(krank,k),
+-     1                            ifrescal,scal,a(krank,k))
+-              enddo ! k
+-            endif
+-c
+-c
+-c           Update the sums-of-squares array ss.
+-c
+-            do k = krank,n
+-              ss(k) = ss(k)-a(krank,k)*conjg(a(krank,k))
+-            enddo ! k
+-c
+-c
+-c           Find the pivot (column with the greatest sum of squares
+-c           of its entries).
+-c
+-            ssmax = 0
+-            kpiv = krank+1
+-c
+-            if(krank .lt. n) then
+-c
+-              do k = krank+1,n
+-c
+-                if(ss(k) .gt. ssmax) then
+-                  ssmax = ss(k)
+-                  kpiv = k
+-                endif
+-c
+-              enddo ! k
+-c
+-            endif ! krank .lt. n
+-c
+-c
+-c           Recompute the sums-of-squares and the pivot
+-c           when ssmax first falls below
+-c           sqrt((1000*feps)^2) * ssmaxin
+-c           and when ssmax first falls below
+-c           ((1000*feps)^2) * ssmaxin.
+-c
+-            if(
+-     1       (ssmax .lt. sqrt((1000*feps)**2) * ssmaxin
+-     2        .and. nupdate .eq. 0) .or.
+-     3       (ssmax .lt. ((1000*feps)**2) * ssmaxin
+-     4        .and. nupdate .eq. 1)
+-     5      ) then
+-c
+-              nupdate = nupdate+1
+-c
+-              ssmax = 0
+-              kpiv = krank+1
+-c
+-              if(krank .lt. n) then
+-c
+-                do k = krank+1,n
+-c
+-                  ss(k) = 0
+-                  do j = krank+1,m
+-                    ss(k) = ss(k)+a(j,k)*conjg(a(j,k))
+-                  enddo ! j
+-c
+-                  if(ss(k) .gt. ssmax) then
+-                    ssmax = ss(k)
+-                    kpiv = k
+-                  endif
+-c
+-                enddo ! k
+-c
+-              endif ! krank .lt. n
+-c
+-            endif
+-c
+-c
+-          endif ! krank .lt. m
+-c
+-c
+-        goto 1000
+- 2000   continue
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzr_qrpiv(m,n,a,krank,ind,ss)
+-c
+-c       computes the pivoted QR decomposition
+-c       of the matrix input into a, using Householder transformations,
+-c       _i.e._, transforms the matrix a from its input value in
+-c       to the matrix out with entry
+-c
+-c                               m
+-c       out(j,indprod(k))  =  Sigma  q(l,j) * in(l,k),
+-c                              l=1
+-c
+-c       for all j = 1, ..., krank, and k = 1, ..., n,
+-c
+-c       where in = the a from before the routine runs,
+-c       out = the a from after the routine runs,
+-c       out(j,k) = 0 when j > k (so that out is triangular),
+-c       q(1:m,1), ..., q(1:m,krank) are orthonormal,
+-c       indprod is the product of the permutations given by ind,
+-c       (as computable via the routine permmult,
+-c       with the permutation swapping 1 and ind(1) taken leftmost
+-c       in the product, that swapping 2 and ind(2) taken next leftmost,
+-c       ..., that swapping krank and ind(krank) taken rightmost),
+-c       and with the matrix out satisfying
+-c
+-c                  min(m,n,krank)
+-c       in(j,k)  =     Sigma      q(j,l) * out(l,indprod(k))
+-c                       l=1
+-c
+-c                +  epsilon(j,k),
+-c
+-c       for all j = 1, ..., m, and k = 1, ..., n,
+-c
+-c       for some matrix epsilon whose norm is (hopefully) minimized
+-c       by the pivoting procedure.
+-c       Well, technically, this routine outputs the Householder vectors
+-c       (or, rather, their second through last entries)
+-c       in the part of a that is supposed to get zeroed, that is,
+-c       in a(j,k) with m >= j > k >= 1.
+-c
+-c       input:
+-c       m -- first dimension of a and q
+-c       n -- second dimension of a
+-c       a -- matrix whose QR decomposition gets computed
+-c       krank -- desired rank of the output matrix
+-c                (please note that if krank > m or krank > n,
+-c                then the rank of the output matrix will be
+-c                less than krank)
+-c
+-c       output:
+-c       a -- triangular (R) factor in the QR decompositon
+-c            of the matrix input into the same storage locations,
+-c            with the Householder vectors stored in the part of a
+-c            that would otherwise consist entirely of zeroes, that is,
+-c            in a(j,k) with m >= j > k >= 1
+-c       ind(k) -- index of the k^th pivot vector;
+-c                 the following code segment will correctly rearrange
+-c                 the product b of q and the upper triangle of out
+-c                 so that b matches the input matrix in
+-c                 to relative precision eps:
+-c
+-c                 copy the non-rearranged product of q and out into b
+-c                 set k to krank
+-c                 [start of loop]
+-c                   swap b(1:m,k) and b(1:m,ind(k))
+-c                   decrement k by 1
+-c                 if k > 0, then go to [start of loop]
+-c
+-c       work:
+-c       ss -- must be at least n real*8 words long
+-c
+-c       _N.B._: This routine outputs the Householder vectors
+-c       (or, rather, their second through last entries)
+-c       in the part of a that is supposed to get zeroed, that is,
+-c       in a(j,k) with m >= j > k >= 1.
+-c
+-c       reference:
+-c       Golub and Van Loan, "Matrix Computations," 3rd edition,
+-c            Johns Hopkins University Press, 1996, Chapter 5.
+-c
+-        implicit none
+-        integer n,m,ind(n),krank,k,j,kpiv,mm,nupdate,ifrescal,
+-     1          loops,loop
+-        real*8 ss(n),ssmax,scal,ssmaxin,rswap,feps
+-        complex*16 a(m,n),cswap
+-c
+-c
+-        feps = .1d-16
+-c
+-c
+-c       Compute the sum of squares of the entries in each column of a,
+-c       the maximum of all such sums, and find the first pivot
+-c       (column with the greatest such sum).
+-c
+-        ssmax = 0
+-        kpiv = 1
+-c
+-        do k = 1,n
+-c
+-          ss(k) = 0
+-          do j = 1,m
+-            ss(k) = ss(k)+a(j,k)*conjg(a(j,k))
+-          enddo ! j
+-c
+-          if(ss(k) .gt. ssmax) then
+-            ssmax = ss(k)
+-            kpiv = k
+-          endif
+-c
+-        enddo ! k
+-c
+-        ssmaxin = ssmax
+-c
+-        nupdate = 0
+-c
+-c
+-c       Set loops = min(krank,m,n).
+-c
+-        loops = krank
+-        if(m .lt. loops) loops = m
+-        if(n .lt. loops) loops = n
+-c
+-        do loop = 1,loops
+-c
+-c
+-          mm = m-loop+1
+-c
+-c
+-c         Perform the pivoting.
+-c
+-          ind(loop) = kpiv
+-c
+-c         Swap a(1:m,loop) and a(1:m,kpiv).
+-c
+-          do j = 1,m
+-            cswap = a(j,loop)
+-            a(j,loop) = a(j,kpiv)
+-            a(j,kpiv) = cswap
+-          enddo ! j
+-c
+-c         Swap ss(loop) and ss(kpiv).
+-c
+-          rswap = ss(loop)
+-          ss(loop) = ss(kpiv)
+-          ss(kpiv) = rswap
+-c
+-c
+-          if(loop .lt. m) then
+-c
+-c
+-c           Compute the data for the Householder transformation
+-c           which will zero a(loop+1,loop), ..., a(m,loop)
+-c           when applied to a, replacing a(loop,loop)
+-c           with the first entry of the result of the application
+-c           of the Householder matrix to a(loop:m,loop),
+-c           and storing entries 2 to mm of the Householder vector
+-c           in a(loop+1,loop), ..., a(m,loop)
+-c           (which otherwise would get zeroed upon application
+-c           of the Householder transformation).
+-c
+-            call idz_house(mm,a(loop,loop),a(loop,loop),
+-     1                     a(loop+1,loop),scal)
+-            ifrescal = 0
+-c
+-c
+-c           Apply the Householder transformation
+-c           to the lower right submatrix of a
+-c           with upper leftmost entry at position (loop,loop+1).
+-c
+-            if(loop .lt. n) then
+-              do k = loop+1,n
+-                call idz_houseapp(mm,a(loop+1,loop),a(loop,k),
+-     1                            ifrescal,scal,a(loop,k))
+-              enddo ! k
+-            endif
+-c
+-c
+-c           Update the sums-of-squares array ss.
+-c
+-            do k = loop,n
+-              ss(k) = ss(k)-a(loop,k)*conjg(a(loop,k))
+-            enddo ! k
+-c
+-c
+-c           Find the pivot (column with the greatest sum of squares
+-c           of its entries).
+-c
+-            ssmax = 0
+-            kpiv = loop+1
+-c
+-            if(loop .lt. n) then
+-c
+-              do k = loop+1,n
+-c
+-                if(ss(k) .gt. ssmax) then
+-                  ssmax = ss(k)
+-                  kpiv = k
+-                endif
+-c
+-              enddo ! k
+-c
+-            endif ! loop .lt. n
+-c
+-c
+-c           Recompute the sums-of-squares and the pivot
+-c           when ssmax first falls below
+-c           sqrt((1000*feps)^2) * ssmaxin
+-c           and when ssmax first falls below
+-c           ((1000*feps)^2) * ssmaxin.
+-c
+-            if(
+-     1       (ssmax .lt. sqrt((1000*feps)**2) * ssmaxin
+-     2        .and. nupdate .eq. 0) .or.
+-     3       (ssmax .lt. ((1000*feps)**2) * ssmaxin
+-     4        .and. nupdate .eq. 1)
+-     5      ) then
+-c
+-              nupdate = nupdate+1
+-c
+-              ssmax = 0
+-              kpiv = loop+1
+-c
+-              if(loop .lt. n) then
+-c
+-                do k = loop+1,n
+-c
+-                  ss(k) = 0
+-                  do j = loop+1,m
+-                    ss(k) = ss(k)+a(j,k)*conjg(a(j,k))
+-                  enddo ! j
+-c
+-                  if(ss(k) .gt. ssmax) then
+-                    ssmax = ss(k)
+-                    kpiv = k
+-                  endif
+-c
+-                enddo ! k
+-c
+-              endif ! loop .lt. n
+-c
+-            endif
+-c
+-c
+-          endif ! loop .lt. m
+-c
+-c
+-        enddo ! loop
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idz_sfft.f b/scipy/linalg/src/id_dist/src/idz_sfft.f
+deleted file mode 100644
+index c8dd9ab18..000000000
+--- a/scipy/linalg/src/id_dist/src/idz_sfft.f
++++ /dev/null
+@@ -1,210 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idz_sffti initializes routine idz_sfft.
+-c
+-c       routine idz_sfft rapidly computes a subset of the entries
+-c       of the DFT of a vector, composed with permutation matrices
+-c       both on input and on output.
+-c
+-c       routine idz_ldiv finds the greatest integer less than or equal
+-c       to a specified integer, that is divisible by another (larger)
+-c       specified integer.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idz_ldiv(l,n,m)
+-c
+-c       finds the greatest integer less than or equal to l
+-c       that divides n.
+-c
+-c       input:
+-c       l -- integer at least as great as m
+-c       n -- integer divisible by m
+-c
+-c       output:
+-c       m -- greatest integer less than or equal to l that divides n
+-c
+-        implicit none
+-        integer n,l,m
+-c
+-c
+-        m = l
+-c
+- 1000   continue
+-        if(m*(n/m) .eq. n) goto 2000
+-c
+-          m = m-1
+-          goto 1000
+-c
+- 2000   continue
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_sffti(l,ind,n,wsave)
+-c
+-c       initializes wsave for use with routine idz_sfft.
+-c
+-c       input:
+-c       l -- number of entries in the output of idz_sfft to compute
+-c       ind -- indices of the entries in the output of idz_sfft
+-c              to compute
+-c       n -- length of the vector to be transformed
+-c
+-c       output:
+-c       wsave -- array needed by routine idz_sfft for processing
+-c
+-        implicit none
+-        integer l,ind(l),n,nblock,ii,m,idivm,imodm,i,j,k
+-        real*8 r1,twopi,fact
+-        complex*16 wsave(2*l+15+3*n),ci,twopii
+-c
+-        ci = (0,1)
+-        r1 = 1
+-        twopi = 2*4*atan(r1)
+-        twopii = twopi*ci
+-c
+-c
+-c       Determine the block lengths for the FFTs.
+-c
+-        call idz_ldiv(l,n,nblock)
+-        m = n/nblock
+-c
+-c
+-c       Initialize wsave for use with routine zfftf.
+-c
+-        call zffti(nblock,wsave)
+-c
+-c
+-c       Calculate the coefficients in the linear combinations
+-c       needed for the direct portion of the calculation.
+-c
+-        fact = 1/sqrt(r1*n)
+-c
+-        ii = 2*l+15
+-c
+-        do j = 1,l
+-c
+-          i = ind(j)
+-c
+-          idivm = (i-1)/m
+-          imodm = (i-1)-m*idivm
+-c
+-          do k = 1,m
+-            wsave(ii+m*(j-1)+k) = exp(-twopii*imodm*(k-1)/(r1*m))
+-     1       * exp(-twopii*(k-1)*idivm/(r1*n)) * fact
+-          enddo ! k
+-c
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_sfft(l,ind,n,wsave,v)
+-c
+-c       computes a subset of the entries of the DFT of v,
+-c       composed with permutation matrices both on input and on output,
+-c       via a two-stage procedure (routine zfftf2 is supposed
+-c       to calculate the full vector from which idz_sfft returns
+-c       a subset of the entries, when zfftf2 has the same parameter
+-c       nblock as in the present routine).
+-c
+-c       input:
+-c       l -- number of entries in the output to compute
+-c       ind -- indices of the entries of the output to compute
+-c       n -- length of v
+-c       v -- vector to be transformed
+-c       wsave -- processing array initialized by routine idz_sffti
+-c
+-c       output:
+-c       v -- entries indexed by ind are given their appropriate
+-c            transformed values
+-c
+-c       _N.B._: The user has to boost the memory allocations
+-c               for wsave (and change iii accordingly) if s/he wishes
+-c               to use strange sizes of n; it's best to stick to powers
+-c               of 2.
+-c
+-c       references:
+-c       Sorensen and Burrus, "Efficient computation of the DFT with
+-c            only a subset of input or output points,"
+-c            IEEE Transactions on Signal Processing, 41 (3): 1184-1200,
+-c            1993.
+-c       Woolfe, Liberty, Rokhlin, Tygert, "A fast randomized algorithm
+-c            for the approximation of matrices," Applied and
+-c            Computational Harmonic Analysis, 25 (3): 335-366, 2008;
+-c            Section 3.3.
+-c
+-        implicit none
+-        integer n,m,l,k,j,ind(l),i,idivm,nblock,ii,iii
+-        real*8 r1,twopi
+-        complex*16 v(n),wsave(2*l+15+3*n),ci,sum
+-c
+-        ci = (0,1)
+-        r1 = 1
+-        twopi = 2*4*atan(r1)
+-c
+-c
+-c       Determine the block lengths for the FFTs.
+-c
+-        call idz_ldiv(l,n,nblock)
+-c
+-c
+-        m = n/nblock
+-c
+-c
+-c       FFT each block of length nblock of v.
+-c
+-        do k = 1,m
+-          call zfftf(nblock,v(nblock*(k-1)+1),wsave)
+-        enddo ! k
+-c
+-c
+-c       Transpose v to obtain wsave(2*l+15+2*n+1 : 2*l+15+3*n).
+-c
+-        iii = 2*l+15+2*n
+-c
+-        do k = 1,m
+-          do j = 1,nblock
+-            wsave(iii+m*(j-1)+k) = v(nblock*(k-1)+j)
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-c       Directly calculate the desired entries of v.
+-c
+-        ii = 2*l+15
+-        iii = 2*l+15+2*n
+-c
+-        do j = 1,l
+-c
+-          i = ind(j)
+-c
+-          idivm = (i-1)/m
+-c
+-          sum = 0
+-c
+-          do k = 1,m
+-            sum = sum + wsave(ii+m*(j-1)+k) * wsave(iii+m*idivm+k)
+-          enddo ! k
+-c
+-          v(i) = sum
+-c
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idz_snorm.f b/scipy/linalg/src/id_dist/src/idz_snorm.f
+deleted file mode 100644
+index 9fe713d47..000000000
+--- a/scipy/linalg/src/id_dist/src/idz_snorm.f
++++ /dev/null
+@@ -1,407 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idz_snorm estimates the spectral norm
+-c       of a matrix specified by routines for applying the matrix
+-c       and its adjoint to arbitrary vectors. This routine uses
+-c       the power method with a random starting vector.
+-c
+-c       routine idz_diffsnorm estimates the spectral norm
+-c       of the difference between two matrices specified by routines
+-c       for applying the matrices and their adjoints
+-c       to arbitrary vectors. This routine uses
+-c       the power method with a random starting vector.
+-c
+-c       routine idz_enorm calculates the Euclidean norm of a vector.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idz_snorm(m,n,matveca,p1a,p2a,p3a,p4a,
+-     1                       matvec,p1,p2,p3,p4,its,snorm,v,u)
+-c
+-c       estimates the spectral norm of a matrix a specified
+-c       by a routine matvec for applying a to an arbitrary vector,
+-c       and by a routine matveca for applying a^*
+-c       to an arbitrary vector. This routine uses the power method
+-c       with a random starting vector.
+-c
+-c       input:
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       matveca -- routine which applies the adjoint of a
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matveca(m,x,n,y,p1a,p2a,p3a,p4a),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the adjoint of a
+-c                  is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the adjoint of a and x,
+-c                  and p1a, p2a, p3a, and p4a are user-specified
+-c                  parameters
+-c       p1a -- parameter to be passed to routine matveca
+-c       p2a -- parameter to be passed to routine matveca
+-c       p3a -- parameter to be passed to routine matveca
+-c       p4a -- parameter to be passed to routine matveca
+-c       matvec -- routine which applies the matrix a
+-c                 to an arbitrary vector; this routine must have
+-c                 a calling sequence of the form
+-c
+-c                 matvec(n,x,m,y,p1,p2,p3,p4),
+-c
+-c                 where n is the length of x,
+-c                 x is the vector to which a is to be applied,
+-c                 m is the length of y,
+-c                 y is the product of a and x,
+-c                 and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvec
+-c       p2 -- parameter to be passed to routine matvec
+-c       p3 -- parameter to be passed to routine matvec
+-c       p4 -- parameter to be passed to routine matvec
+-c       its -- number of iterations of the power method to conduct
+-c
+-c       output:
+-c       snorm -- estimate of the spectral norm of a
+-c       v -- estimate of a normalized right singular vector
+-c            corresponding to the greatest singular value of a
+-c
+-c       work:
+-c       u -- must be at least m complex*16 elements long
+-c
+-c       reference:
+-c       Kuczynski and Wozniakowski, "Estimating the largest eigenvalue
+-c            by the power and Lanczos algorithms with a random start,"
+-c            SIAM Journal on Matrix Analysis and Applications,
+-c            13 (4): 1992, 1094-1122.
+-c
+-        implicit none
+-        integer m,n,its,it,n2,k
+-        real*8 snorm,enorm
+-        complex*16 p1a,p2a,p3a,p4a,p1,p2,p3,p4,u(m),v(n)
+-        external matveca,matvec
+-c
+-c
+-c       Fill the real and imaginary parts of each entry
+-c       of the initial vector v with i.i.d. random variables
+-c       drawn uniformly from [-1,1].
+-c
+-        n2 = 2*n
+-        call id_srand(n2,v)
+-c
+-        do k = 1,n
+-          v(k) = 2*v(k)-1
+-        enddo ! k
+-c
+-c
+-c       Normalize v.
+-c
+-        call idz_enorm(n,v,enorm)
+-c
+-        do k = 1,n
+-          v(k) = v(k)/enorm
+-        enddo ! k
+-c
+-c
+-        do it = 1,its
+-c
+-c         Apply a to v, obtaining u.
+-c
+-          call matvec(n,v,m,u,p1,p2,p3,p4)
+-c
+-c         Apply a^* to u, obtaining v.
+-c
+-          call matveca(m,u,n,v,p1a,p2a,p3a,p4a)
+-c
+-c         Normalize v.
+-c
+-          call idz_enorm(n,v,snorm)
+-c
+-          if(snorm .ne. 0) then
+-c
+-            do k = 1,n
+-              v(k) = v(k)/snorm
+-            enddo ! k
+-c
+-          endif
+-c
+-          snorm = sqrt(snorm)
+-c
+-        enddo ! it
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_enorm(n,v,enorm)
+-c
+-c       computes the Euclidean norm of v, the square root
+-c       of the sum of the squares of the absolute values
+-c       of the entries of v.
+-c
+-c       input:
+-c       n -- length of v
+-c       v -- vector whose Euclidean norm is to be calculated
+-c
+-c       output:
+-c       enorm -- Euclidean norm of v
+-c
+-        implicit none
+-        integer n,k
+-        real*8 enorm
+-        complex*16 v(n)
+-c
+-c
+-        enorm = 0
+-c
+-        do k = 1,n
+-          enorm = enorm+v(k)*conjg(v(k))
+-        enddo ! k
+-c
+-        enorm = sqrt(enorm)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_diffsnorm(m,n,matveca,p1a,p2a,p3a,p4a,
+-     1                           matveca2,p1a2,p2a2,p3a2,p4a2,
+-     2                           matvec,p1,p2,p3,p4,
+-     3                           matvec2,p12,p22,p32,p42,its,snorm,w)
+-c
+-c       estimates the spectral norm of the difference between matrices
+-c       a and a2, where a is specified by routines matvec and matveca
+-c       for applying a and a^* to arbitrary vectors,
+-c       and a2 is specified by routines matvec2 and matveca2
+-c       for applying a2 and (a2)^* to arbitrary vectors.
+-c       This routine uses the power method
+-c       with a random starting vector.
+-c
+-c       input:
+-c       m -- number of rows in a, as well as the number of rows in a2
+-c       n -- number of columns in a, as well as the number of columns
+-c            in a2
+-c       matveca -- routine which applies the adjoint of a
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matveca(m,x,n,y,p1a,p2a,p3a,p4a),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the adjoint of a
+-c                  is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the adjoint of a and x,
+-c                  and p1a, p2a, p3a, and p4a are user-specified
+-c                  parameters
+-c       p1a -- parameter to be passed to routine matveca
+-c       p2a -- parameter to be passed to routine matveca
+-c       p3a -- parameter to be passed to routine matveca
+-c       p4a -- parameter to be passed to routine matveca
+-c       matveca2 -- routine which applies the adjoint of a2
+-c                   to an arbitrary vector; this routine must have
+-c                   a calling sequence of the form
+-c
+-c                   matveca2(m,x,n,y,p1a2,p2a2,p3a2,p4a2),
+-c
+-c                   where m is the length of x,
+-c                   x is the vector to which the adjoint of a2
+-c                   is to be applied,
+-c                   n is the length of y,
+-c                   y is the product of the adjoint of a2 and x,
+-c                   and p1a2, p2a2, p3a2, and p4a2 are user-specified
+-c                   parameters
+-c       p1a2 -- parameter to be passed to routine matveca2
+-c       p2a2 -- parameter to be passed to routine matveca2
+-c       p3a2 -- parameter to be passed to routine matveca2
+-c       p4a2 -- parameter to be passed to routine matveca2
+-c       matvec -- routine which applies the matrix a
+-c                 to an arbitrary vector; this routine must have
+-c                 a calling sequence of the form
+-c
+-c                 matvec(n,x,m,y,p1,p2,p3,p4),
+-c
+-c                 where n is the length of x,
+-c                 x is the vector to which a is to be applied,
+-c                 m is the length of y,
+-c                 y is the product of a and x,
+-c                 and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvec
+-c       p2 -- parameter to be passed to routine matvec
+-c       p3 -- parameter to be passed to routine matvec
+-c       p4 -- parameter to be passed to routine matvec
+-c       matvec2 -- routine which applies the matrix a2
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matvec2(n,x,m,y,p12,p22,p32,p42),
+-c
+-c                  where n is the length of x,
+-c                  x is the vector to which a2 is to be applied,
+-c                  m is the length of y,
+-c                  y is the product of a2 and x, and
+-c                  p12, p22, p32, and p42 are user-specified parameters
+-c       p12 -- parameter to be passed to routine matvec2
+-c       p22 -- parameter to be passed to routine matvec2
+-c       p32 -- parameter to be passed to routine matvec2
+-c       p42 -- parameter to be passed to routine matvec2
+-c       its -- number of iterations of the power method to conduct
+-c
+-c       output:
+-c       snorm -- estimate of the spectral norm of a-a2
+-c
+-c       work:
+-c       w -- must be at least 3*m+3*n complex*16 elements long
+-c
+-c       reference:
+-c       Kuczynski and Wozniakowski, "Estimating the largest eigenvalue
+-c            by the power and Lanczos algorithms with a random start,"
+-c            SIAM Journal on Matrix Analysis and Applications,
+-c            13 (4): 1992, 1094-1122.
+-c
+-        implicit none
+-        integer m,n,its,lw,iu,lu,iu1,lu1,iu2,lu2,
+-     1          iv,lv,iv1,lv1,iv2,lv2
+-        real*8 snorm
+-        complex*16 p1a,p2a,p3a,p4a,p1a2,p2a2,p3a2,p4a2,
+-     1             p1,p2,p3,p4,p12,p22,p32,p42,w(3*m+3*n)
+-        external matveca,matvec,matveca2,matvec2
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw = 0
+-c
+-        iu = lw+1
+-        lu = m
+-        lw = lw+lu
+-c
+-        iu1 = lw+1
+-        lu1 = m
+-        lw = lw+lu1
+-c
+-        iu2 = lw+1
+-        lu2 = m
+-        lw = lw+lu2
+-c
+-        iv = lw+1
+-        lv = n
+-        lw = lw+1
+-c
+-        iv1 = lw+1
+-        lv1 = n
+-        lw = lw+lv1
+-c
+-        iv2 = lw+1
+-        lv2 = n
+-        lw = lw+lv2
+-c
+-c
+-        call idz_diffsnorm0(m,n,matveca,p1a,p2a,p3a,p4a,
+-     1                      matveca2,p1a2,p2a2,p3a2,p4a2,
+-     2                      matvec,p1,p2,p3,p4,
+-     3                      matvec2,p12,p22,p32,p42,
+-     4                      its,snorm,w(iu),w(iu1),w(iu2),
+-     5                      w(iv),w(iv1),w(iv2))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_diffsnorm0(m,n,matveca,p1a,p2a,p3a,p4a,
+-     1                            matveca2,p1a2,p2a2,p3a2,p4a2,
+-     2                            matvec,p1,p2,p3,p4,
+-     3                            matvec2,p12,p22,p32,p42,
+-     4                            its,snorm,u,u1,u2,v,v1,v2)
+-c
+-c       routine idz_diffsnorm serves as a memory wrapper
+-c       for the present routine. (Please see routine idz_diffsnorm
+-c       for further documentation.)
+-c
+-        implicit none
+-        integer m,n,its,it,n2,k
+-        real*8 snorm,enorm
+-        complex*16 p1a,p2a,p3a,p4a,p1a2,p2a2,p3a2,p4a2,
+-     1             p1,p2,p3,p4,p12,p22,p32,p42,u(m),u1(m),u2(m),
+-     2             v(n),v1(n),v2(n)
+-        external matveca,matvec,matveca2,matvec2
+-c
+-c
+-c       Fill the real and imaginary parts of each entry
+-c       of the initial vector v with i.i.d. random variables
+-c       drawn uniformly from [-1,1].
+-c
+-        n2 = 2*n
+-        call id_srand(n2,v)
+-c
+-        do k = 1,n
+-          v(k) = 2*v(k)-1
+-        enddo ! k
+-c
+-c
+-c       Normalize v.
+-c
+-        call idz_enorm(n,v,enorm)
+-c
+-        do k = 1,n
+-          v(k) = v(k)/enorm
+-        enddo ! k
+-c
+-c
+-        do it = 1,its
+-c
+-c         Apply a and a2 to v, obtaining u1 and u2.
+-c
+-          call matvec(n,v,m,u1,p1,p2,p3,p4)
+-          call matvec2(n,v,m,u2,p12,p22,p32,p42)
+-c
+-c         Form u = u1-u2.
+-c
+-          do k = 1,m
+-            u(k) = u1(k)-u2(k)
+-          enddo ! k
+-c
+-c         Apply a^* and (a2)^* to u, obtaining v1 and v2.
+-c
+-          call matveca(m,u,n,v1,p1a,p2a,p3a,p4a)
+-          call matveca2(m,u,n,v2,p1a2,p2a2,p3a2,p4a2)
+-c
+-c         Form v = v1-v2.
+-c
+-          do k = 1,n
+-            v(k) = v1(k)-v2(k)
+-          enddo ! k
+-c
+-c         Normalize v.
+-c
+-          call idz_enorm(n,v,snorm)
+-c
+-          if(snorm .gt. 0) then
+-c
+-            do k = 1,n
+-              v(k) = v(k)/snorm
+-            enddo ! k
+-c
+-          endif
+-c
+-          snorm = sqrt(snorm)
+-c
+-        enddo ! it
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idz_svd.f b/scipy/linalg/src/id_dist/src/idz_svd.f
+deleted file mode 100644
+index e14cf66a0..000000000
+--- a/scipy/linalg/src/id_dist/src/idz_svd.f
++++ /dev/null
+@@ -1,438 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzr_svd computes an approximation of specified rank
+-c       to a given matrix, in the usual SVD form U S V^*,
+-c       where U has orthonormal columns, V has orthonormal columns,
+-c       and S is diagonal.
+-c
+-c       routine idzp_svd computes an approximation of specified
+-c       precision to a given matrix, in the usual SVD form U S V^*,
+-c       where U has orthonormal columns, V has orthonormal columns,
+-c       and S is diagonal.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idzr_svd(m,n,a,krank,u,v,s,ier,r)
+-c
+-c       constructs a rank-krank SVD  u diag(s) v^*  approximating a,
+-c       where u is an m x krank matrix whose columns are orthonormal,
+-c       v is an n x krank matrix whose columns are orthonormal,
+-c       and diag(s) is a diagonal krank x krank matrix whose entries
+-c       are all nonnegative. This routine combines a QR code
+-c       (which is based on plane/Householder reflections)
+-c       with the LAPACK routine zgesdd.
+-c
+-c       input:
+-c       m -- first dimension of a and u
+-c       n -- second dimension of a, and first dimension of v
+-c       a -- matrix to be SVD'd
+-c       krank -- desired rank of the approximation to a
+-c
+-c       output:
+-c       u -- left singular vectors of a corresponding
+-c            to the k greatest singular values of a
+-c       v -- right singular vectors of a corresponding
+-c            to the k greatest singular values of a
+-c       s -- k greatest singular values of a
+-c       ier -- 0 when the routine terminates successfully;
+-c              nonzero when the routine encounters an error
+-c
+-c       work:
+-c       r -- must be at least
+-c            (krank+2)*n+8*min(m,n)+6*krank**2+8*krank
+-c            complex*16 elements long
+-c
+-c       _N.B._: This routine destroys a. Also, please beware that
+-c               the source code for this routine could be clearer.
+-c
+-        implicit none
+-        character*1 jobz
+-        integer m,n,k,krank,ifadjoint,ldr,ldu,ldvadj,lwork,
+-     1          info,j,ier,io
+-        real*8 s(krank)
+-        complex*16 a(m,n),u(m,krank),v(n*krank),r(*)
+-c
+-c
+-        io = 8*min(m,n)
+-c
+-c
+-        ier = 0
+-c
+-c
+-c       Compute a pivoted QR decomposition of a.
+-c
+-        call idzr_qrpiv(m,n,a,krank,r,r(io+1))
+-c
+-c
+-c       Extract R from the QR decomposition.
+-c
+-        call idz_retriever(m,n,a,krank,r(io+1))
+-c
+-c
+-c       Rearrange R according to ind.
+-c
+-        call idz_permuter(krank,r,krank,n,r(io+1))
+-c
+-c
+-c       Use LAPACK to SVD r,
+-c       storing the krank (krank x 1) left singular vectors
+-c       in r(io+krank*n+1 : io+krank*n+krank*krank).
+-c
+-        jobz = 'S'
+-        ldr = krank
+-        lwork = 2*(krank**2+2*krank+n)
+-        ldu = krank
+-        ldvadj = krank
+-c
+-        call zgesdd(jobz,krank,n,r(io+1),ldr,s,r(io+krank*n+1),ldu,
+-     1              v,ldvadj,r(io+krank*n+krank*krank+1),lwork,
+-     2              r(io+krank*n+krank*krank+lwork+1),r,info)
+-c
+-        if(info .ne. 0) then
+-          ier = info
+-          return
+-        endif
+-c
+-c
+-c       Multiply the U from R from the left by Q to obtain the U
+-c       for A.
+-c
+-        do k = 1,krank
+-c
+-          do j = 1,krank
+-            u(j,k) = r(io+krank*n+j+krank*(k-1))
+-          enddo ! j
+-c
+-          do j = krank+1,m
+-            u(j,k) = 0
+-          enddo ! j
+-c
+-        enddo ! k
+-c
+-        ifadjoint = 0
+-        call idz_qmatmat(ifadjoint,m,n,a,krank,krank,u,r)
+-c
+-c
+-c       Take the adjoint of v to obtain r.
+-c
+-        call idz_adjer(krank,n,v,r)
+-c
+-c
+-c       Copy r into v.
+-c
+-        do k = 1,n*krank
+-          v(k) = r(k)
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzp_svd(lw,eps,m,n,a,krank,iu,iv,is,w,ier)
+-c
+-c       constructs a rank-krank SVD  U Sigma V^*  approximating a
+-c       to precision eps, where U is an m x krank matrix whose
+-c       columns are orthonormal, V is an n x krank matrix whose
+-c       columns are orthonormal, and Sigma is a diagonal krank x krank
+-c       matrix whose entries are all nonnegative.
+-c       The entries of U are stored in w, starting at w(iu);
+-c       the entries of V are stored in w, starting at w(iv).
+-c       The diagonal entries of Sigma are stored in w,
+-c       starting at w(is). This routine combines a QR code
+-c       (which is based on plane/Householder reflections)
+-c       with the LAPACK routine zgesdd.
+-c
+-c       input:
+-c       lw -- maximum usable length of w (in complex*16 elements)
+-c       eps -- precision to which the SVD approximates a
+-c       m -- first dimension of a and u
+-c       n -- second dimension of a, and first dimension of v
+-c       a -- matrix to be SVD'd
+-c
+-c       output:
+-c       krank -- rank of the approximation to a
+-c       iu -- index in w of the first entry of the matrix
+-c             of orthonormal left singular vectors of a
+-c       iv -- index in w of the first entry of the matrix
+-c             of orthonormal right singular vectors of a
+-c       is -- index in w of the first entry of the array
+-c             of singular values of a; the singular values are stored
+-c             as complex*16 numbers whose imaginary parts are zeros
+-c       w -- array containing the singular values and singular vectors
+-c            of a; w doubles as a work array, and so must be at least
+-c            (krank+1)*(m+2*n+9)+8*min(m,n)+6*krank**2
+-c            complex*16 elements long, where krank is the rank
+-c            output by the present routine
+-c       ier -- 0 when the routine terminates successfully;
+-c              -1000 when lw is too small;
+-c              other nonzero values when zgesdd bombs
+-c
+-c       _N.B._: This routine destroys a. Also, please beware that
+-c               the source code for this routine could be clearer.
+-c               w must be at least
+-c               (krank+1)*(m+2*n+9)+8*min(m,n)+6*krank**2
+-c               complex*16 elements long, where krank is the rank
+-c               output by the present routine.
+-c
+-        implicit none
+-        character*1 jobz
+-        integer m,n,k,krank,ifadjoint,ldr,ldu,ldvadj,lwork,
+-     1          info,j,ier,io,iu,iv,is,ivi,isi,lu,lv,ls,lw
+-        real*8 eps
+-        complex*16 a(m,n),w(*)
+-c
+-c
+-        io = 8*min(m,n)
+-c
+-c
+-        ier = 0
+-c
+-c
+-c       Compute a pivoted QR decomposition of a.
+-c
+-        call idzp_qrpiv(eps,m,n,a,krank,w,w(io+1))
+-c
+-c
+-        if(krank .gt. 0) then
+-c
+-c
+-c         Extract R from the QR decomposition.
+-c
+-          call idz_retriever(m,n,a,krank,w(io+1))
+-c
+-c
+-c         Rearrange R according to ind.
+-c
+-          call idz_permuter(krank,w,krank,n,w(io+1))
+-c
+-c
+-c         Use LAPACK to SVD R,
+-c         storing the krank (krank x 1) left singular vectors
+-c         in w(io+krank*n+1 : io+krank*n+krank*krank).
+-c
+-          jobz = 'S'
+-          ldr = krank
+-          lwork = 2*(krank**2+2*krank+n)
+-          ldu = krank
+-          ldvadj = krank
+-c
+-          ivi = io+krank*n+krank*krank+lwork+3*krank**2+4*krank+1
+-          lv = n*krank
+-c
+-          isi = ivi+lv
+-          ls = krank
+-c
+-          if(lw .lt. isi+ls+m*krank-1) then
+-            ier = -1000
+-            return
+-          endif
+-c
+-          call zgesdd(jobz,krank,n,w(io+1),ldr,w(isi),w(io+krank*n+1),
+-     1                ldu,w(ivi),ldvadj,w(io+krank*n+krank*krank+1),
+-     2                lwork,w(io+krank*n+krank*krank+lwork+1),w,info)
+-c
+-          if(info .ne. 0) then
+-            ier = info
+-            return
+-          endif
+-c
+-c
+-c         Take the adjoint of w(ivi:ivi+lv-1) to obtain V.
+-c
+-          iv = 1
+-          call idz_adjer(krank,n,w(ivi),w(iv))
+-c
+-c
+-c         Copy w(isi:isi+ls/2) into w(is:is+ls-1).
+-c
+-          is = iv+lv
+-c
+-          call idz_realcomp(ls,w(isi),w(is))
+-c
+-c
+-c         Multiply the U from R from the left by Q to obtain the U
+-c         for A.
+-c
+-          iu = is+ls
+-          lu = m*krank
+-c
+-          do k = 1,krank
+-c
+-            do j = 1,krank
+-              w(iu-1+j+krank*(k-1)) = w(io+krank*n+j+krank*(k-1))
+-            enddo ! j
+-c
+-          enddo ! k
+-c
+-          do k = krank,1,-1
+-c
+-            do j = m,krank+1,-1
+-              w(iu-1+j+m*(k-1)) = 0
+-            enddo ! j
+-c
+-            do j = krank,1,-1
+-              w(iu-1+j+m*(k-1)) = w(iu-1+j+krank*(k-1))
+-            enddo ! j
+-c
+-          enddo ! k
+-c
+-          ifadjoint = 0
+-          call idz_qmatmat(ifadjoint,m,n,a,krank,krank,w(iu),
+-     1                     w(iu+lu+1))
+-c
+-c
+-        endif ! krank .gt. 0
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_realcomp(n,a,b)
+-c
+-c       copies the real*8 array a into the complex*16 array b.
+-c
+-c       input:
+-c       n -- length of a and b
+-c       a -- real*8 array to be copied into b
+-c
+-c       output:
+-c       b -- complex*16 copy of a
+-c
+-        integer n,k
+-        real*8 a(n)
+-        complex*16 b(n)
+-c
+-c
+-        do k = 1,n
+-          b(k) = a(k)
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_permuter(krank,ind,m,n,a)
+-c
+-c       permutes the columns of a according to ind obtained
+-c       from routine idzr_qrpiv or idzp_qrpiv, assuming that
+-c       a = q r from idzr_qrpiv or idzp_qrpiv.
+-c
+-c       input:
+-c       krank -- rank specified to routine idzr_qrpiv
+-c                or obtained from routine idzp_qrpiv
+-c       ind -- indexing array obtained from routine idzr_qrpiv
+-c              or idzp_qrpiv
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       a -- matrix to be rearranged
+-c
+-c       output:
+-c       a -- rearranged matrix
+-c
+-        implicit none
+-        integer k,krank,m,n,j,ind(krank)
+-        complex*16 cswap,a(m,n)
+-c
+-c
+-        do k = krank,1,-1
+-          do j = 1,m
+-c
+-            cswap = a(j,k)
+-            a(j,k) = a(j,ind(k))
+-            a(j,ind(k)) = cswap
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_retriever(m,n,a,krank,r)
+-c
+-c       extracts R in the QR decomposition specified by the output a
+-c       of the routine idzr_qrpiv or idzp_qrpiv
+-c
+-c       input:
+-c       m -- first dimension of a
+-c       n -- second dimension of a and r
+-c       a -- output of routine idzr_qrpiv or idzp_qrpiv
+-c       krank -- rank specified to routine idzr_qrpiv,
+-c                or output by routine idzp_qrpiv
+-c
+-c       output:
+-c       r -- triangular factor in the QR decomposition specified
+-c            by the output a of the routine idzr_qrpiv or idzp_qrpiv
+-c
+-        implicit none
+-        integer m,n,j,k,krank
+-        complex*16 a(m,n),r(krank,n)
+-c
+-c
+-c       Copy a into r and zero out the appropriate
+-c       Householder vectors that are stored in one triangle of a.
+-c
+-        do k = 1,n
+-          do j = 1,krank
+-            r(j,k) = a(j,k)
+-          enddo ! j
+-        enddo ! k
+-c
+-        do k = 1,n
+-          if(k .lt. krank) then
+-            do j = k+1,krank
+-              r(j,k) = 0
+-            enddo ! j
+-          endif
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_adjer(m,n,a,aa)
+-c
+-c       forms the adjoint aa of a.
+-c
+-c       input:
+-c       m -- first dimension of a and second dimension of aa
+-c       n -- second dimension of a and first dimension of aa
+-c       a -- matrix whose adjoint is to be taken
+-c
+-c       output:
+-c       aa -- adjoint of a
+-c
+-        implicit none
+-        integer m,n,j,k
+-        complex*16 a(m,n),aa(n,m)
+-c
+-c
+-        do k = 1,n
+-          do j = 1,m
+-            aa(k,j) = conjg(a(j,k))
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idzp_aid.f b/scipy/linalg/src/id_dist/src/idzp_aid.f
+deleted file mode 100644
+index 784b40cde..000000000
+--- a/scipy/linalg/src/id_dist/src/idzp_aid.f
++++ /dev/null
+@@ -1,390 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzp_aid computes the ID, to a specified precision,
+-c       of an arbitrary matrix. This routine is randomized.
+-c
+-c       routine idz_estrank estimates the numerical rank,
+-c       to a specified precision, of an arbitrary matrix.
+-c       This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idzp_aid(eps,m,n,a,work,krank,list,proj)
+-c
+-c       computes the ID of the matrix a, i.e., lists in list
+-c       the indices of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                        krank
+-c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
+-c                         l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon dimensioned epsilon(m,n-krank)
+-c       such that the greatest singular value of epsilon
+-c       <= the greatest singular value of a * eps.
+-c
+-c       input:
+-c       eps -- precision to which the ID is to be computed
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       a -- matrix to be decomposed; the present routine does not
+-c            alter a
+-c       work -- initialization array that has been constructed
+-c               by routine idz_frmi
+-c
+-c       output:
+-c       krank -- numerical rank of a to precision eps
+-c       list -- indices of the columns in the ID
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns
+-c               in the original matrix being ID'd;
+-c               proj doubles as a work array in the present routine, so
+-c               proj must be at least n*(2*n2+1)+n2+1 complex*16
+-c               elements long, where n2 is the greatest integer
+-c               less than or equal to m, such that n2 is
+-c               a positive integer power of two.
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c               proj must be at least n*(2*n2+1)+n2+1 complex*16
+-c               elements long, where n2 is the greatest integer
+-c               less than or equal to m, such that n2 is
+-c               a positive integer power of two.
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,n,list(n),krank,kranki,n2
+-        real*8 eps
+-        complex*16 a(m,n),proj(*),work(17*m+70)
+-c
+-c
+-c       Allocate memory in proj.
+-c
+-        n2 = work(2)
+-c
+-c
+-c       Find the rank of a.
+-c
+-        call idz_estrank(eps,m,n,a,work,kranki,proj)
+-c
+-c
+-        if(kranki .eq. 0) call idzp_aid0(eps,m,n,a,krank,list,proj,
+-     1                                   proj(m*n+1))
+-c
+-        if(kranki .ne. 0) call idzp_aid1(eps,n2,n,kranki,proj,
+-     1                                   krank,list,proj(n2*n+1))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzp_aid0(eps,m,n,a,krank,list,proj,rnorms)
+-c
+-c       uses routine idzp_id to ID a without modifying its entries
+-c       (in contrast to the usual behavior of idzp_id).
+-c
+-c       input:
+-c       eps -- precision of the decomposition to be constructed
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c
+-c       output:
+-c       krank -- numerical rank of the ID
+-c       list -- indices of the columns in the ID
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns in a;
+-c               proj doubles as a work array in the present routine, so
+-c               must be at least m*n complex*16 elements long
+-c
+-c       work:
+-c       rnorms -- must be at least n real*8 elements long
+-c
+-c       _N.B._: proj must be at least m*n complex*16 elements long
+-c
+-        implicit none
+-        integer m,n,krank,list(n),j,k
+-        real*8 eps,rnorms(n)
+-        complex*16 a(m,n),proj(m,n)
+-c
+-c
+-c       Copy a into proj.
+-c
+-        do k = 1,n
+-          do j = 1,m
+-            proj(j,k) = a(j,k)
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-c       ID proj.
+-c
+-        call idzp_id(eps,m,n,proj,krank,list,rnorms)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzp_aid1(eps,n2,n,kranki,proj,krank,list,rnorms)
+-c
+-c       IDs the uppermost kranki x n block of the n2 x n matrix
+-c       input as proj.
+-c
+-c       input:
+-c       eps -- precision of the decomposition to be constructed
+-c       n2 -- first dimension of proj as input
+-c       n -- second dimension of proj as input
+-c       kranki -- number of rows to extract from proj
+-c       proj -- matrix containing the kranki x n block to be ID'd
+-c
+-c       output:
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns
+-c               in the original matrix being ID'd
+-c       krank -- numerical rank of the ID
+-c       list -- indices of the columns in the ID
+-c
+-c       work:
+-c       rnorms -- must be at least n real*8 elements long
+-c
+-        implicit none
+-        integer n,n2,kranki,krank,list(n),j,k
+-        real*8 eps,rnorms(n)
+-        complex*16 proj(n2*n)
+-c
+-c
+-c       Move the uppermost kranki x n block of the n2 x n matrix proj
+-c       to the beginning of proj.
+-c
+-        do k = 1,n
+-          do j = 1,kranki
+-            proj(j+kranki*(k-1)) = proj(j+n2*(k-1))
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-c       ID proj.
+-c
+-        call idzp_id(eps,kranki,n,proj,krank,list,rnorms)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_estrank(eps,m,n,a,w,krank,ra)
+-c
+-c       estimates the numerical rank krank of an m x n matrix a
+-c       to precision eps. This routine applies n2 random vectors
+-c       to a, obtaining ra, where n2 is the greatest integer
+-c       less than or equal to m such that n2 is a positive integer
+-c       power of two. krank is typically about 8 higher than
+-c       the actual numerical rank.
+-c
+-c       input:
+-c       eps -- precision defining the numerical rank
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       a -- matrix whose rank is to be estimated
+-c       w -- initialization array that has been constructed
+-c            by routine idz_frmi
+-c
+-c       output:
+-c       krank -- estimate of the numerical rank of a;
+-c                this routine returns krank = 0 when the actual
+-c                numerical rank is nearly full (that is,
+-c                greater than n - 8 or n2 - 8)
+-c       ra -- product of an n2 x m random matrix and the m x n matrix
+-c             a, where n2 is the greatest integer less than or equal
+-c             to m such that n2 is a positive integer power of two;
+-c             ra doubles as a work array in the present routine, and so
+-c             must be at least n*n2+(n+1)*(n2+1) complex*16 elements
+-c             long
+-c
+-c       _N.B._: ra must be at least n*n2+(n2+1)*(n+1) complex*16
+-c               elements long for use in the present routine
+-c               (here, n2 is the greatest integer less than or equal
+-c               to m, such that n2 is a positive integer power of two).
+-c               This routine returns krank = 0 when the actual
+-c               numerical rank is nearly full.
+-c
+-        implicit none
+-        integer m,n,krank,n2,irat,lrat,iscal,lscal,ira,lra,lra2
+-        real*8 eps
+-        complex*16 a(m,n),ra(*),w(17*m+70)
+-c
+-c
+-c       Extract from the array w initialized by routine idz_frmi
+-c       the greatest integer less than or equal to m that is
+-c       a positive integer power of two.
+-c
+-        n2 = w(2)
+-c
+-c
+-c       Allocate memory in ra.
+-c
+-        lra = 0
+-c
+-        ira = lra+1
+-        lra2 = n2*n
+-        lra = lra+lra2
+-c
+-        irat = lra+1
+-        lrat = n*(n2+1)
+-        lra = lra+lrat
+-c
+-        iscal = lra+1
+-        lscal = n2+1
+-        lra = lra+lscal
+-c
+-        call idz_estrank0(eps,m,n,a,w,n2,krank,ra(ira),ra(irat),
+-     1                    ra(iscal))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_estrank0(eps,m,n,a,w,n2,krank,ra,rat,scal)
+-c
+-c       routine idz_estrank serves as a memory wrapper
+-c       for the present routine. (Please see routine idz_estrank
+-c       for further documentation.)
+-c
+-        implicit none
+-        integer m,n,n2,krank,ifrescal,k,nulls,j
+-        real*8 eps,scal(n2+1),ss,ssmax
+-        complex*16 a(m,n),ra(n2,n),residual,w(17*m+70),rat(n,n2+1)
+-c
+-c
+-c       Apply the random matrix to every column of a, obtaining ra.
+-c
+-        do k = 1,n
+-          call idz_frm(m,n2,w,a(1,k),ra(1,k))
+-        enddo ! k
+-c
+-c
+-c       Compute the sum of squares of the entries in each column of ra
+-c       and the maximum of all such sums.
+-c
+-        ssmax = 0
+-c
+-        do k = 1,n
+-c
+-          ss = 0
+-          do j = 1,m
+-            ss = ss+a(j,k)*conjg(a(j,k))
+-          enddo ! j
+-c
+-          if(ss .gt. ssmax) ssmax = ss
+-c
+-        enddo ! k
+-c
+-c
+-c       Transpose ra to obtain rat.
+-c
+-        call idz_transposer(n2,n,ra,rat)
+-c
+-c
+-        krank = 0
+-        nulls = 0
+-c
+-c
+-c       Loop until nulls = 7, krank+nulls = n2, or krank+nulls = n.
+-c
+- 1000   continue
+-c
+-c
+-          if(krank .gt. 0) then
+-c
+-c           Apply the previous Householder transformations
+-c           to rat(:,krank+1).
+-c
+-            ifrescal = 0
+-c
+-            do k = 1,krank
+-              call idz_houseapp(n-k+1,rat(1,k),rat(k,krank+1),
+-     1                          ifrescal,scal(k),rat(k,krank+1))
+-            enddo ! k
+-c
+-          endif ! krank .gt. 0
+-c
+-c
+-c         Compute the Householder vector associated
+-c         with rat(krank+1:*,krank+1).
+-c
+-          call idz_house(n-krank,rat(krank+1,krank+1),
+-     1                   residual,rat(1,krank+1),scal(krank+1))
+-c
+-c
+-          krank = krank+1
+-          if(abs(residual) .le. eps*sqrt(ssmax)) nulls = nulls+1
+-c
+-c
+-        if(nulls .lt. 7 .and. krank+nulls .lt. n2
+-     1   .and. krank+nulls .lt. n)
+-     2   goto 1000
+-c
+-c
+-        if(nulls .lt. 7) krank = 0
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_transposer(m,n,a,at)
+-c
+-c       transposes a to obtain at.
+-c
+-c       input:
+-c       m -- first dimension of a, and second dimension of at
+-c       n -- second dimension of a, and first dimension of at
+-c       a -- matrix to be transposed
+-c
+-c       output:
+-c       at -- transpose of a
+-c
+-        implicit none
+-        integer m,n,j,k
+-        complex*16 a(m,n),at(n,m)
+-c
+-c
+-        do k = 1,n
+-          do j = 1,m
+-c
+-            at(k,j) = a(j,k)
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idzp_asvd.f b/scipy/linalg/src/id_dist/src/idzp_asvd.f
+deleted file mode 100644
+index 4704f5bbd..000000000
+--- a/scipy/linalg/src/id_dist/src/idzp_asvd.f
++++ /dev/null
+@@ -1,207 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzp_asvd computes the SVD, to a specified precision,
+-c       of an arbitrary matrix. This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idzp_asvd(lw,eps,m,n,a,winit,krank,iu,iv,is,w,ier)
+-c
+-c       constructs a rank-krank SVD  U Sigma V^*  approximating a
+-c       to precision eps, where U is an m x krank matrix whose
+-c       columns are orthonormal, V is an n x krank matrix whose
+-c       columns are orthonormal, and Sigma is a diagonal krank x krank
+-c       matrix whose entries are all nonnegative.
+-c       The entries of U are stored in w, starting at w(iu);
+-c       the entries of V are stored in w, starting at w(iv).
+-c       The diagonal entries of Sigma are stored in w,
+-c       starting at w(is). This routine uses a randomized algorithm.
+-c
+-c       input:
+-c       lw -- maximum usable length (in complex*16 elements)
+-c             of the array w
+-c       eps -- precision of the desired approximation
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       a -- matrix to be approximated; the present routine does not
+-c            alter a
+-c       winit -- initialization array that has been constructed
+-c                by routine idz_frmi
+-c
+-c       output:
+-c       krank -- rank of the SVD constructed
+-c       iu -- index in w of the first entry of the matrix
+-c             of orthonormal left singular vectors of a
+-c       iv -- index in w of the first entry of the matrix
+-c             of orthonormal right singular vectors of a
+-c       is -- index in w of the first entry of the array
+-c             of singular values of a
+-c       w -- array containing the singular values and singular vectors
+-c            of a; w doubles as a work array, and so must be at least
+-c            max( (krank+1)*(3*m+5*n+11)+8*krank**2, (2*n+1)*(n2+1) )
+-c            complex*16 elements long, where n2 is the greatest integer
+-c            less than or equal to m, such that n2 is
+-c            a positive integer power of two; krank is the rank output
+-c            by this routine
+-c       ier -- 0 when the routine terminates successfully;
+-c              -1000 when lw is too small;
+-c              other nonzero values when idz_id2svd bombs
+-c
+-c       _N.B._: w must be at least
+-c               max( (krank+1)*(3*m+5*n+11)+8*krank^2, (2*n+1)*(n2+1) )
+-c               complex*16 elements long, where n2 is
+-c               the greatest integer less than or equal to m,
+-c               such that n2 is a positive integer power of two;
+-c               krank is the rank output by this routine.
+-c               Also, the algorithm used by this routine is randomized.
+-c
+-        implicit none
+-        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
+-     1          iwork,lwork,k,ier,lw2,iu,iv,is,iui,ivi,isi,lu,lv,ls
+-        real*8 eps
+-        complex*16 a(m,n),winit(17*m+70),w(*)
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw2 = 0
+-c
+-        ilist = lw2+1
+-        llist = n
+-        lw2 = lw2+llist
+-c
+-        iproj = lw2+1
+-c
+-c
+-c       ID a.
+-c
+-        call idzp_aid(eps,m,n,a,winit,krank,w(ilist),w(iproj))
+-c
+-c
+-        if(krank .gt. 0) then
+-c
+-c
+-c         Allocate more memory in w.
+-c
+-          lproj = krank*(n-krank)
+-          lw2 = lw2+lproj
+-c
+-          icol = lw2+1
+-          lcol = m*krank
+-          lw2 = lw2+lcol
+-c
+-          iui = lw2+1
+-          lu = m*krank
+-          lw2 = lw2+lu
+-c
+-          ivi = lw2+1
+-          lv = n*krank
+-          lw2 = lw2+lv
+-c
+-          isi = lw2+1
+-          ls = krank
+-          lw2 = lw2+ls
+-c
+-          iwork = lw2+1
+-          lwork = (krank+1)*(m+3*n+10)+9*krank**2
+-          lw2 = lw2+lwork
+-c
+-c
+-          if(lw .lt. lw2) then
+-            ier = -1000
+-            return
+-          endif
+-c
+-c
+-          call idzp_asvd0(m,n,a,krank,w(ilist),w(iproj),
+-     1                    w(iui),w(ivi),w(isi),ier,w(icol),w(iwork))
+-          if(ier .ne. 0) return
+-c
+-c
+-          iu = 1
+-          iv = iu+lu
+-          is = iv+lv
+-c
+-c
+-c         Copy the singular values and singular vectors
+-c         into their proper locations.
+-c
+-          do k = 1,lu
+-            w(iu+k-1) = w(iui+k-1)
+-          enddo ! k
+-c
+-          do k = 1,lv
+-            w(iv+k-1) = w(ivi+k-1)
+-          enddo ! k
+-c
+-          call idz_realcomplex(ls,w(isi),w(is))
+-c
+-c
+-        endif ! krank .gt. 0
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzp_asvd0(m,n,a,krank,list,proj,u,v,s,ier,
+-     1                        col,work)
+-c
+-c       routine idzp_asvd serves as a memory wrapper
+-c       for the present routine (please see routine idzp_asvd
+-c       for further documentation).
+-c
+-        implicit none
+-        integer m,n,krank,list(n),ier
+-        real*8 s(krank)
+-        complex*16 a(m,n),u(m,krank),v(n,krank),
+-     1             proj(krank,n-krank),col(m,krank),
+-     2             work((krank+1)*(m+3*n+10)+9*krank**2)
+-c
+-c
+-c       Collect together the columns of a indexed by list into col.
+-c
+-        call idz_copycols(m,n,a,krank,list,col)
+-c
+-c
+-c       Convert the ID to an SVD.
+-c
+-        call idz_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_realcomplex(n,a,b)
+-c
+-c       copies the real*8 array a into the complex*16 array b.
+-c
+-c       input:
+-c       n -- length of a and b
+-c       a -- real*8 array to be copied into b
+-c
+-c       output:
+-c       b -- complex*16 copy of a
+-c
+-        integer n,k
+-        real*8 a(n)
+-        complex*16 b(n)
+-c
+-c
+-        do k = 1,n
+-          b(k) = a(k)
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idzp_rid.f b/scipy/linalg/src/id_dist/src/idzp_rid.f
+deleted file mode 100644
+index f12623aed..000000000
+--- a/scipy/linalg/src/id_dist/src/idzp_rid.f
++++ /dev/null
+@@ -1,379 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzp_rid computes the ID, to a specified precision,
+-c       of a matrix specified by a routine for applying its adjoint
+-c       to arbitrary vectors. This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idzp_rid(lproj,eps,m,n,matveca,p1,p2,p3,p4,
+-     1                      krank,list,proj,ier)
+-c
+-c       computes the ID of a, i.e., lists in list the indices
+-c       of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                        krank
+-c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
+-c                         l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon dimensioned epsilon(m,n-krank)
+-c       such that the greatest singular value of epsilon
+-c       <= the greatest singular value of a * eps.
+-c
+-c       input:
+-c       lproj -- maximum usable length (in complex*16 elements)
+-c                of the array proj
+-c       eps -- precision to which the ID is to be computed
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       matveca -- routine which applies the adjoint
+-c                  of the matrix to be ID'd to an arbitrary vector;
+-c                  this routine must have a calling sequence
+-c                  of the form
+-c
+-c                  matveca(m,x,n,y,p1,p2,p3,p4),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the adjoint
+-c                  of the matrix is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the adjoint of the matrix and x,
+-c                  and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matveca
+-c       p2 -- parameter to be passed to routine matveca
+-c       p3 -- parameter to be passed to routine matveca
+-c       p4 -- parameter to be passed to routine matveca
+-c
+-c       output:
+-c       krank -- numerical rank
+-c       list -- indices of the columns in the ID
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns
+-c               in the original matrix being ID'd;
+-c               the present routine uses proj as a work array, too, so
+-c               proj must be at least m+1 + 2*n*(krank+1) complex*16
+-c               elements long, where krank is the rank output
+-c               by the present routine
+-c       ier -- 0 when the routine terminates successfully;
+-c              -1000 when lproj is too small
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c               proj must be at least m+1 + 2*n*(krank+1) complex*16
+-c               elements long, where krank is the rank output
+-c               by the present routine.
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,n,list(n),krank,lw,iwork,lwork,ira,kranki,lproj,
+-     1          lra,ier,k
+-        real*8 eps
+-        complex*16 p1,p2,p3,p4,proj(*)
+-        external matveca
+-c
+-c
+-        ier = 0
+-c
+-c
+-c       Allocate memory in proj.
+-c
+-        lw = 0
+-c
+-        iwork = lw+1
+-        lwork = m+2*n+1
+-        lw = lw+lwork
+-c
+-        ira = lw+1
+-c
+-c
+-c       Find the rank of a.
+-c
+-        lra = lproj-lwork
+-        call idz_findrank(lra,eps,m,n,matveca,p1,p2,p3,p4,
+-     1                    kranki,proj(ira),ier,proj(iwork))
+-        if(ier .ne. 0) return
+-c
+-c
+-        if(lproj .lt. lwork+2*kranki*n) then
+-          ier = -1000
+-          return
+-        endif
+-c
+-c
+-c       Take the adjoint of ra.
+-c
+-        call idz_adjointer(n,kranki,proj(ira),proj(ira+kranki*n))
+-c
+-c
+-c       Move the adjoint thus obtained to the beginning of proj.
+-c
+-        do k = 1,kranki*n
+-          proj(k) = proj(ira+kranki*n+k-1)
+-        enddo ! k
+-c
+-c
+-c       ID the adjoint.
+-c
+-        call idzp_id(eps,kranki,n,proj,krank,list,proj(1+kranki*n))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_findrank(lra,eps,m,n,matveca,p1,p2,p3,p4,
+-     1                          krank,ra,ier,w)
+-c
+-c       estimates the numerical rank krank of a matrix a to precision
+-c       eps, where the routine matveca applies the adjoint of a
+-c       to an arbitrary vector. This routine applies the adjoint of a
+-c       to krank random vectors, and returns the resulting vectors
+-c       as the columns of ra.
+-c
+-c       input:
+-c       lra -- maximum usable length (in complex*16 elements)
+-c              of array ra
+-c       eps -- precision defining the numerical rank
+-c       m -- first dimension of a
+-c       n -- second dimension of a
+-c       matveca -- routine which applies the adjoint
+-c                  of the matrix whose rank is to be estimated
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matveca(m,x,n,y,p1,p2,p3,p4),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the adjoint
+-c                  of the matrix is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the adjoint of the matrix and x,
+-c                  and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matveca
+-c       p2 -- parameter to be passed to routine matveca
+-c       p3 -- parameter to be passed to routine matveca
+-c       p4 -- parameter to be passed to routine matveca
+-c
+-c       output:
+-c       krank -- estimate of the numerical rank of a
+-c       ra -- product of the adjoint of a and a matrix whose entries
+-c             are pseudorandom realizations of i.i.d. random numbers,
+-c             uniformly distributed on [0,1];
+-c             ra must be at least 2*n*krank complex*16 elements long
+-c       ier -- 0 when the routine terminates successfully;
+-c              -1000 when lra is too small
+-c
+-c       work:
+-c       w -- must be at least m+2*n+1 complex*16 elements long
+-c
+-c       _N.B._: ra must be at least 2*n*krank complex*16 elements long.
+-c               Also, the algorithm used by this routine is randomized.
+-c
+-        implicit none
+-        integer m,n,lw,krank,ix,lx,iy,ly,iscal,lscal,lra,ier
+-        real*8 eps
+-        complex*16 p1,p2,p3,p4,ra(n,*),w(m+2*n+1)
+-        external matveca
+-c
+-c
+-        lw = 0
+-c
+-        ix = lw+1
+-        lx = m
+-        lw = lw+lx
+-c
+-        iy = lw+1
+-        ly = n
+-        lw = lw+ly
+-c
+-        iscal = lw+1
+-        lscal = n+1
+-        lw = lw+lscal
+-c
+-c
+-        call idz_findrank0(lra,eps,m,n,matveca,p1,p2,p3,p4,
+-     1                     krank,ra,ier,w(ix),w(iy),w(iscal))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_findrank0(lra,eps,m,n,matveca,p1,p2,p3,p4,
+-     1                           krank,ra,ier,x,y,scal)
+-c
+-c       routine idz_findrank serves as a memory wrapper
+-c       for the present routine. (Please see routine idz_findrank
+-c       for further documentation.)
+-c
+-        implicit none
+-        integer m,n,krank,ifrescal,k,lra,ier,m2
+-        real*8 eps,enorm
+-        complex*16 x(m),ra(n,2,*),p1,p2,p3,p4,scal(n+1),y(n),residual
+-        external matveca
+-c
+-c
+-        ier = 0
+-c
+-c
+-        krank = 0
+-c
+-c
+-c       Loop until the relative residual is greater than eps,
+-c       or krank = m or krank = n.
+-c
+- 1000   continue
+-c
+-c
+-          if(lra .lt. n*2*(krank+1)) then
+-            ier = -1000
+-            return
+-          endif
+-c
+-c
+-c         Apply the adjoint of a to a random vector.
+-c
+-          m2 = m*2
+-          call id_srand(m2,x)
+-          call matveca(m,x,n,ra(1,1,krank+1),p1,p2,p3,p4)
+-c
+-          do k = 1,n
+-            y(k) = ra(k,1,krank+1)
+-          enddo ! k
+-c
+-c
+-          if(krank .eq. 0) then
+-c
+-c           Compute the Euclidean norm of y.
+-c
+-            enorm = 0
+-c
+-            do k = 1,n
+-              enorm = enorm + y(k)*conjg(y(k))
+-            enddo ! k
+-c
+-            enorm = sqrt(enorm)
+-c
+-          endif ! krank .eq. 0
+-c
+-c
+-          if(krank .gt. 0) then
+-c
+-c           Apply the previous Householder transformations to y.
+-c
+-            ifrescal = 0
+-c
+-            do k = 1,krank
+-              call idz_houseapp(n-k+1,ra(1,2,k),y(k),
+-     1                          ifrescal,scal(k),y(k))
+-            enddo ! k
+-c
+-          endif ! krank .gt. 0
+-c
+-c
+-c         Compute the Householder vector associated with y.
+-c
+-          call idz_house(n-krank,y(krank+1),
+-     1                   residual,ra(1,2,krank+1),scal(krank+1))
+-c
+-c
+-          krank = krank+1
+-c
+-c
+-        if(abs(residual) .gt. eps*enorm
+-     1   .and. krank .lt. m .and. krank .lt. n)
+-     2   goto 1000
+-c
+-c
+-c       Delete the Householder vectors from the array ra.
+-c
+-        call idz_crunch(n,krank,ra)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_crunch(n,l,a)
+-c
+-c       removes every other block of n entries from a vector.
+-c
+-c       input:
+-c       n -- length of each block to remove
+-c       l -- half of the total number of blocks
+-c       a -- original array
+-c
+-c       output:
+-c       a -- array with every other block of n entries removed
+-c
+-        implicit none
+-        integer j,k,n,l
+-        complex*16 a(n,2*l)
+-c
+-c
+-        do j = 2,l
+-          do k = 1,n
+-c
+-            a(k,j) = a(k,2*j-1)
+-c
+-          enddo ! k
+-        enddo ! j
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_adjointer(m,n,a,aa)
+-c
+-c       forms the adjoint aa of a.
+-c
+-c       input:
+-c       m -- first dimension of a, and second dimension of aa
+-c       n -- second dimension of a, and first dimension of aa
+-c       a -- matrix whose adjoint is to be taken
+-c
+-c       output:
+-c       aa -- adjoint of a
+-c
+-        implicit none
+-        integer m,n,j,k
+-        complex*16 a(m,n),aa(n,m)
+-c
+-c
+-        do k = 1,n
+-          do j = 1,m
+-c
+-            aa(k,j) = conjg(a(j,k))
+-c
+-          enddo ! j
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idzp_rsvd.f b/scipy/linalg/src/id_dist/src/idzp_rsvd.f
+deleted file mode 100644
+index e34b3e374..000000000
+--- a/scipy/linalg/src/id_dist/src/idzp_rsvd.f
++++ /dev/null
+@@ -1,244 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzp_rsvd computes the SVD, to a specified precision,
+-c       of a matrix specified by routines for applying the matrix
+-c       and its adjoint to arbitrary vectors.
+-c       This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idzp_rsvd(lw,eps,m,n,matveca,p1t,p2t,p3t,p4t,
+-     1                       matvec,p1,p2,p3,p4,krank,iu,iv,is,w,ier)
+-c
+-c       constructs a rank-krank SVD  U Sigma V^*  approximating a
+-c       to precision eps, where matveca is a routine which applies a^*
+-c       to an arbitrary vector, and matvec is a routine
+-c       which applies a to an arbitrary vector; U is an m x krank
+-c       matrix whose columns are orthonormal, V is an n x krank
+-c       matrix whose columns are orthonormal, and Sigma is a diagonal
+-c       krank x krank matrix whose entries are all nonnegative.
+-c       The entries of U are stored in w, starting at w(iu);
+-c       the entries of V are stored in w, starting at w(iv).
+-c       The diagonal entries of Sigma are stored in w,
+-c       starting at w(is). This routine uses a randomized algorithm.
+-c
+-c       input:
+-c       lw -- maximum usable length (in complex*16 elements)
+-c             of the array w
+-c       eps -- precision of the desired approximation
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       matveca -- routine which applies the adjoint
+-c                  of the matrix to be SVD'd
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matveca(m,x,n,y,p1t,p2t,p3t,p4t),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the adjoint
+-c                  of the matrix is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the adjoint of the matrix and x,
+-c                  and p1t, p2t, p3t, and p4t are user-specified
+-c                  parameters
+-c       p1t -- parameter to be passed to routine matveca
+-c       p2t -- parameter to be passed to routine matveca
+-c       p3t -- parameter to be passed to routine matveca
+-c       p4t -- parameter to be passed to routine matveca
+-c       matvec -- routine which applies the matrix to be SVD'd
+-c                 to an arbitrary vector; this routine must have
+-c                 a calling sequence of the form
+-c
+-c                 matvec(n,x,m,y,p1,p2,p3,p4),
+-c
+-c                 where n is the length of x,
+-c                 x is the vector to which the matrix is to be applied,
+-c                 m is the length of y,
+-c                 y is the product of the matrix and x,
+-c                 and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvec
+-c       p2 -- parameter to be passed to routine matvec
+-c       p3 -- parameter to be passed to routine matvec
+-c       p4 -- parameter to be passed to routine matvec
+-c
+-c       output:
+-c       krank -- rank of the SVD constructed
+-c       iu -- index in w of the first entry of the matrix
+-c             of orthonormal left singular vectors of a
+-c       iv -- index in w of the first entry of the matrix
+-c             of orthonormal right singular vectors of a
+-c       is -- index in w of the first entry of the array
+-c             of singular values of a; the singular values are stored
+-c             as complex*16 numbers whose imaginary parts are zeros
+-c       w -- array containing the singular values and singular vectors
+-c            of a; w doubles as a work array, and so must be at least
+-c            (krank+1)*(3*m+5*n+11)+8*krank^2 complex*16 elements long,
+-c            where krank is the rank returned by the present routine
+-c       ier -- 0 when the routine terminates successfully;
+-c              -1000 when lw is too small;
+-c              other nonzero values when idz_id2svd bombs
+-c
+-c       _N.B._: w must be at least (krank+1)*(3*m+5*n+11)+8*krank**2
+-c               complex*16 elements long, where krank is the rank
+-c               returned by the present routine. Also, the algorithm
+-c               used by the present routine is randomized.
+-c
+-        implicit none
+-        integer m,n,krank,lw,lw2,ilist,llist,iproj,icol,lcol,lp,
+-     1          iwork,lwork,ier,lproj,iu,iv,is,lu,lv,ls,iui,ivi,isi,k
+-        real*8 eps
+-        complex*16 p1t,p2t,p3t,p4t,p1,p2,p3,p4,w(*)
+-        external matveca,matvec
+-c
+-c
+-c       Allocate some memory.
+-c
+-        lw2 = 0
+-c
+-        ilist = lw2+1
+-        llist = n
+-        lw2 = lw2+llist
+-c
+-        iproj = lw2+1
+-c
+-c
+-c       ID a.
+-c
+-        lp = lw-lw2
+-        call idzp_rid(lp,eps,m,n,matveca,p1t,p2t,p3t,p4t,krank,
+-     1                w(ilist),w(iproj),ier)
+-        if(ier .ne. 0) return
+-c
+-c
+-        if(krank .gt. 0) then
+-c
+-c
+-c         Allocate more memory.
+-c
+-          lproj = krank*(n-krank)
+-          lw2 = lw2+lproj
+-c
+-          icol = lw2+1
+-          lcol = m*krank
+-          lw2 = lw2+lcol
+-c
+-          iui = lw2+1
+-          lu = m*krank
+-          lw2 = lw2+lu
+-c
+-          ivi = lw2+1
+-          lv = n*krank
+-          lw2 = lw2+lv
+-c
+-          isi = lw2+1
+-          ls = krank
+-          lw2 = lw2+ls
+-c
+-          iwork = lw2+1
+-          lwork = (krank+1)*(m+3*n+10)+9*krank**2
+-          lw2 = lw2+lwork
+-c
+-c
+-          if(lw .lt. lw2) then
+-            ier = -1000
+-            return
+-          endif
+-c
+-c
+-          call idzp_rsvd0(m,n,matveca,p1t,p2t,p3t,p4t,
+-     1                    matvec,p1,p2,p3,p4,krank,w(iui),w(ivi),
+-     2                    w(isi),ier,w(ilist),w(iproj),w(icol),
+-     3                    w(iwork))
+-          if(ier .ne. 0) return
+-c
+-c
+-          iu = 1
+-          iv = iu+lu
+-          is = iv+lv
+-c
+-c
+-c         Copy the singular values and singular vectors
+-c         into their proper locations.
+-c
+-          do k = 1,lu
+-            w(iu+k-1) = w(iui+k-1)
+-          enddo ! k
+-c
+-          do k = 1,lv
+-            w(iv+k-1) = w(ivi+k-1)
+-          enddo ! k
+-c
+-          call idz_reco(ls,w(isi),w(is))
+-c
+-c
+-        endif ! krank .gt. 0
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzp_rsvd0(m,n,matveca,p1t,p2t,p3t,p4t,
+-     1                        matvec,p1,p2,p3,p4,krank,u,v,s,ier,
+-     2                        list,proj,col,work)
+-c
+-c       routine idzp_rsvd serves as a memory wrapper
+-c       for the present routine (please see routine idzp_rsvd
+-c       for further documentation).
+-c
+-        implicit none
+-        integer m,n,krank,list(n),ier
+-        real*8 s(krank)
+-        complex*16 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
+-     1             proj(krank,n-krank),col(m*krank),
+-     2             work((krank+1)*(m+3*n+10)+9*krank**2)
+-        external matveca,matvec
+-c
+-c
+-c       Collect together the columns of a indexed by list into col.
+-c
+-        call idz_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,col,work)
+-c
+-c
+-c       Convert the ID to an SVD.
+-c
+-        call idz_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idz_reco(n,a,b)
+-c
+-c       copies the real*8 array a into the complex*16 array b.
+-c
+-c       input:
+-c       n -- length of a and b
+-c       a -- real*8 array to be copied into b
+-c
+-c       output:
+-c       b -- complex*16 copy of a
+-c
+-        integer n,k
+-        real*8 a(n)
+-        complex*16 b(n)
+-c
+-c
+-        do k = 1,n
+-          b(k) = a(k)
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idzr_aid.f b/scipy/linalg/src/id_dist/src/idzr_aid.f
+deleted file mode 100644
+index e8380ecd3..000000000
+--- a/scipy/linalg/src/id_dist/src/idzr_aid.f
++++ /dev/null
+@@ -1,209 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzr_aid computes the ID, to a specified rank,
+-c       of an arbitrary matrix. This routine is randomized.
+-c
+-c       routine idzr_aidi initializes routine idzr_aid.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idzr_aid(m,n,a,krank,w,list,proj)
+-c
+-c       computes the ID of the matrix a, i.e., lists in list
+-c       the indices of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                       min(m,n,krank)
+-c       a(j,list(k))  =     Sigma      a(j,list(l)) * proj(l,k-krank)(*)
+-c                            l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
+-c       whose norm is (hopefully) minimized by the pivoting procedure.
+-c
+-c       input:
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       a -- matrix to be ID'd; the present routine does not alter a
+-c       krank -- rank of the ID to be constructed
+-c       w -- initialization array that routine idzr_aidi
+-c            has constructed
+-c
+-c       output:
+-c       list -- indices of the columns in the ID
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns
+-c               in the original matrix being ID'd
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,n,krank,list(n),lw,ir,lr,lw2,iw
+-        complex*16 a(m,n),proj(krank*(n-krank)),
+-     1             w((2*krank+17)*n+21*m+80)
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw = 0
+-c
+-        iw = lw+1
+-        lw2 = 21*m+80+n
+-        lw = lw+lw2
+-c
+-        ir = lw+1
+-        lr = (krank+8)*2*n
+-        lw = lw+lr
+-c
+-c
+-        call idzr_aid0(m,n,a,krank,w(iw),list,proj,w(ir))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzr_aid0(m,n,a,krank,w,list,proj,r)
+-c
+-c       routine idzr_aid serves as a memory wrapper
+-c       for the present routine
+-c       (see idzr_aid for further documentation).
+-c
+-        implicit none
+-        integer k,l,m,n2,n,krank,list(n),mn,lproj
+-        complex*16 a(m,n),r(krank+8,2*n),proj(krank,n-krank),
+-     1             w(21*m+80+n)
+-c
+-c       Please note that the second dimension of r is 2*n
+-c       (instead of n) so that if krank+8 >= m/2, then
+-c       we can copy the whole of a into r.
+-c
+-c
+-c       Retrieve the number of random test vectors
+-c       and the greatest integer less than m that is
+-c       a positive integer power of two.
+-c
+-        l = w(1)
+-        n2 = w(2)
+-c
+-c
+-        if(l .lt. n2 .and. l .le. m) then
+-c
+-c         Apply the random matrix.
+-c
+-          do k = 1,n
+-            call idz_sfrm(l,m,n2,w(11),a(1,k),r(1,k))
+-          enddo ! k
+-c
+-c         ID r.
+-c
+-          call idzr_id(l,n,r,krank,list,w(20*m+81))
+-c
+-c         Retrieve proj from r.
+-c
+-          lproj = krank*(n-krank)
+-          call idzr_copyzarr(lproj,r,proj)
+-c
+-        endif
+-c
+-c
+-        if(l .ge. n2 .or. l .gt. m) then
+-c
+-c         ID a directly.
+-c
+-          mn = m*n
+-          call idzr_copyzarr(mn,a,r)
+-          call idzr_id(m,n,r,krank,list,w(20*m+81))
+-c
+-c         Retrieve proj from r.
+-c
+-          lproj = krank*(n-krank)
+-          call idzr_copyzarr(lproj,r,proj)
+-c
+-        endif
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzr_copyzarr(n,a,b)
+-c
+-c       copies a into b.
+-c
+-c       input:
+-c       n -- length of a and b
+-c       a -- array to copy into b
+-c
+-c       output:
+-c       b -- copy of a
+-c
+-        implicit none
+-        integer n,k
+-        complex*16 a(n),b(n)
+-c
+-c
+-        do k = 1,n
+-          b(k) = a(k)
+-        enddo ! k
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzr_aidi(m,n,krank,w)
+-c
+-c       initializes the array w for using routine idzr_aid.
+-c
+-c       input:
+-c       m -- number of rows in the matrix to be ID'd
+-c       n -- number of columns in the matrix to be ID'd
+-c       krank -- rank of the ID to be constructed
+-c
+-c       output:
+-c       w -- initialization array for using routine idzr_aid
+-c
+-        implicit none
+-        integer m,n,krank,l,n2
+-        complex*16 w((2*krank+17)*n+21*m+80)
+-c
+-c
+-c       Set the number of random test vectors to 8 more than the rank.
+-c
+-        l = krank+8
+-        w(1) = l
+-c
+-c
+-c       Initialize the rest of the array w.
+-c
+-        n2 = 0
+-        if(l .le. m) call idz_sfrmi(l,m,n2,w(11))
+-        w(2) = n2
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idzr_asvd.f b/scipy/linalg/src/id_dist/src/idzr_asvd.f
+deleted file mode 100644
+index 55ad61203..000000000
+--- a/scipy/linalg/src/id_dist/src/idzr_asvd.f
++++ /dev/null
+@@ -1,118 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzr_aid computes the SVD, to a specified rank,
+-c       of an arbitrary matrix. This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idzr_asvd(m,n,a,krank,w,u,v,s,ier)
+-c
+-c       constructs a rank-krank SVD  u diag(s) v^*  approximating a,
+-c       where u is an m x krank matrix whose columns are orthonormal,
+-c       v is an n x krank matrix whose columns are orthonormal,
+-c       and diag(s) is a diagonal krank x krank matrix whose entries
+-c       are all nonnegative. This routine uses a randomized algorithm.
+-c
+-c       input:
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       a -- matrix to be decomposed; the present routine does not
+-c            alter a
+-c       krank -- rank of the SVD being constructed
+-c       w -- initialization array that routine idzr_aidi
+-c            has constructed (for use in the present routine,
+-c            w must be at least
+-c            (2*krank+22)*m+(6*krank+21)*n+8*krank**2+10*krank+90
+-c            complex*16 elements long)
+-c
+-c       output:
+-c       u -- matrix of orthonormal left singular vectors of a
+-c       v -- matrix of orthonormal right singular vectors of a
+-c       s -- array of singular values of a
+-c       ier -- 0 when the routine terminates successfully;
+-c              nonzero otherwise
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c
+-        implicit none
+-        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
+-     1          iwork,lwork,iwinit,lwinit,ier
+-        real*8 s(krank)
+-        complex*16 a(m,n),u(m,krank),v(n,krank),
+-     1             w((2*krank+22)*m+(6*krank+21)*n+8*krank**2
+-     2              +10*krank+90)
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw = 0
+-c
+-        iwinit = lw+1
+-        lwinit = (2*krank+17)*n+21*m+80
+-        lw = lw+lwinit
+-c
+-        ilist = lw+1
+-        llist = n
+-        lw = lw+llist
+-c
+-        iproj = lw+1
+-        lproj = krank*(n-krank)
+-        lw = lw+lproj
+-c
+-        icol = lw+1
+-        lcol = m*krank
+-        lw = lw+lcol
+-c
+-        iwork = lw+1
+-        lwork = (krank+1)*(m+3*n+10)+9*krank**2
+-        lw = lw+lwork
+-c
+-c
+-        call idzr_asvd0(m,n,a,krank,w(iwinit),u,v,s,ier,
+-     1                  w(ilist),w(iproj),w(icol),w(iwork))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzr_asvd0(m,n,a,krank,winit,u,v,s,ier,
+-     1                        list,proj,col,work)
+-c
+-c       routine idzr_asvd serves as a memory wrapper
+-c       for the present routine (please see routine idzr_asvd
+-c       for further documentation).
+-c
+-        implicit none
+-        integer m,n,krank,list(n),ier
+-        real*8 s(krank)
+-        complex*16 a(m,n),u(m,krank),v(n,krank),
+-     1             proj(krank,n-krank),col(m*krank),
+-     2             winit((2*krank+17)*n+21*m+80),
+-     3             work((krank+1)*(m+3*n+10)+9*krank**2)
+-c
+-c
+-c       ID a.
+-c
+-        call idzr_aid(m,n,a,krank,winit,list,proj)
+-c
+-c
+-c       Collect together the columns of a indexed by list into col.
+-c
+-        call idz_copycols(m,n,a,krank,list,col)
+-c
+-c
+-c       Convert the ID to an SVD.
+-c
+-        call idz_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idzr_rid.f b/scipy/linalg/src/id_dist/src/idzr_rid.f
+deleted file mode 100644
+index cf8fcaacf..000000000
+--- a/scipy/linalg/src/id_dist/src/idzr_rid.f
++++ /dev/null
+@@ -1,156 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzr_rid computes the ID, to a specified rank,
+-c       of a matrix specified by a routine for applying its adjoint
+-c       to arbitrary vectors. This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idzr_rid(m,n,matveca,p1,p2,p3,p4,krank,list,proj)
+-c
+-c       computes the ID of a matrix "a" specified by
+-c       the routine matveca -- matveca must apply the adjoint
+-c       of the matrix being ID'd to an arbitrary vector --
+-c       i.e., the present routine lists in list the indices
+-c       of krank columns of a such that
+-c
+-c       a(j,list(k))  =  a(j,list(k))
+-c
+-c       for all j = 1, ..., m; k = 1, ..., krank, and
+-c
+-c                       min(m,n,krank)
+-c       a(j,list(k))  =     Sigma      a(j,list(l)) * proj(l,k-krank)(*)
+-c                            l=1
+-c
+-c                     +  epsilon(j,k-krank)
+-c
+-c       for all j = 1, ..., m; k = krank+1, ..., n,
+-c
+-c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
+-c       whose norm is (hopefully) minimized by the pivoting procedure.
+-c
+-c       input:
+-c       m -- number of rows in the matrix to be ID'd
+-c       n -- number of columns in the matrix to be ID'd
+-c       matveca -- routine which applies the adjoint
+-c                  of the matrix to be ID'd to an arbitrary vector;
+-c                  this routine must have a calling sequence
+-c                  of the form
+-c
+-c                  matveca(m,x,n,y,p1,p2,p3,p4),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the adjoint
+-c                  of the matrix is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the adjoint of the matrix and x,
+-c                  and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matveca
+-c       p2 -- parameter to be passed to routine matveca
+-c       p3 -- parameter to be passed to routine matveca
+-c       p4 -- parameter to be passed to routine matveca
+-c       krank -- rank of the ID to be constructed
+-c
+-c       output:
+-c       list -- indices of the columns in the ID
+-c       proj -- matrix of coefficients needed to interpolate
+-c               from the selected columns to the other columns
+-c               in the original matrix being ID'd;
+-c               proj doubles as a work array in the present routine, so
+-c               proj must be at least m+(krank+3)*n complex*16 elements
+-c               long
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c               proj must be at least m+(krank+3)*n complex*16 elements
+-c               long.
+-c
+-c       reference:
+-c       Halko, Martinsson, Tropp, "Finding structure with randomness:
+-c            probabilistic algorithms for constructing approximate
+-c            matrix decompositions," SIAM Review, 53 (2): 217-288,
+-c            2011.
+-c
+-        implicit none
+-        integer m,n,krank,list(n),lw,ix,lx,iy,ly,ir,lr
+-        complex*16 p1,p2,p3,p4,proj(m+(krank+3)*n)
+-        external matveca
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw = 0
+-c
+-        ir = lw+1
+-        lr = (krank+2)*n
+-        lw = lw+lr
+-c
+-        ix = lw+1
+-        lx = m
+-        lw = lw+lx
+-c
+-        iy = lw+1
+-        ly = n
+-        lw = lw+ly
+-c
+-c
+-        call idzr_ridall0(m,n,matveca,p1,p2,p3,p4,krank,
+-     1                    list,proj(ir),proj(ix),proj(iy))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzr_ridall0(m,n,matveca,p1,p2,p3,p4,krank,
+-     1                          list,r,x,y)
+-c
+-c       routine idzr_ridall serves as a memory wrapper
+-c       for the present routine
+-c       (see idzr_ridall for further documentation).
+-c
+-        implicit none
+-        integer j,k,l,m,n,krank,list(n),m2
+-        complex*16 x(m),y(n),p1,p2,p3,p4,r(krank+2,n)
+-        external matveca
+-c
+-c
+-c       Set the number of random test vectors to 2 more than the rank.
+-c
+-        l = krank+2
+-c
+-c       Apply the adjoint of the original matrix to l random vectors.
+-c
+-        do j = 1,l
+-c
+-c         Generate a random vector.
+-c
+-          m2 = m*2
+-          call id_srand(m2,x)
+-c
+-c         Apply the adjoint of the matrix to x, obtaining y.
+-c
+-          call matveca(m,x,n,y,p1,p2,p3,p4)
+-c
+-c         Copy the conjugate of y into row j of r.
+-c
+-          do k = 1,n
+-            r(j,k) = conjg(y(k))
+-          enddo ! k
+-c
+-        enddo ! j
+-c
+-c
+-c       ID r.
+-c
+-        call idzr_id(l,n,r,krank,list,y)
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/idzr_rsvd.f b/scipy/linalg/src/id_dist/src/idzr_rsvd.f
+deleted file mode 100644
+index d788e219b..000000000
+--- a/scipy/linalg/src/id_dist/src/idzr_rsvd.f
++++ /dev/null
+@@ -1,159 +0,0 @@
+-c       this file contains the following user-callable routines:
+-c
+-c
+-c       routine idzr_rsvd computes the SVD, to a specified rank,
+-c       of a matrix specified by routines for applying the matrix
+-c       and its adjoint to arbitrary vectors.
+-c       This routine is randomized.
+-c
+-c
+-ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+-c
+-c
+-c
+-c
+-        subroutine idzr_rsvd(m,n,matveca,p1t,p2t,p3t,p4t,
+-     1                       matvec,p1,p2,p3,p4,krank,u,v,s,ier,w)
+-c
+-c       constructs a rank-krank SVD  u diag(s) v^*  approximating a,
+-c       where matveca is a routine which applies a^*
+-c       to an arbitrary vector, and matvec is a routine
+-c       which applies a to an arbitrary vector;
+-c       u is an m x krank matrix whose columns are orthonormal,
+-c       v is an n x krank matrix whose columns are orthonormal,
+-c       and diag(s) is a diagonal krank x krank matrix whose entries
+-c       are all nonnegative. This routine uses a randomized algorithm.
+-c
+-c       input:
+-c       m -- number of rows in a
+-c       n -- number of columns in a
+-c       matveca -- routine which applies the adjoint
+-c                  of the matrix to be SVD'd
+-c                  to an arbitrary vector; this routine must have
+-c                  a calling sequence of the form
+-c
+-c                  matveca(m,x,n,y,p1t,p2t,p3t,p4t),
+-c
+-c                  where m is the length of x,
+-c                  x is the vector to which the adjoint
+-c                  of the matrix is to be applied,
+-c                  n is the length of y,
+-c                  y is the product of the adjoint of the matrix and x,
+-c                  and p1t, p2t, p3t, and p4t are user-specified
+-c                  parameters
+-c       p1t -- parameter to be passed to routine matveca
+-c       p2t -- parameter to be passed to routine matveca
+-c       p3t -- parameter to be passed to routine matveca
+-c       p4t -- parameter to be passed to routine matveca
+-c       matvec -- routine which applies the matrix to be SVD'd
+-c                 to an arbitrary vector; this routine must have
+-c                 a calling sequence of the form
+-c
+-c                 matvec(n,x,m,y,p1,p2,p3,p4),
+-c
+-c                 where n is the length of x,
+-c                 x is the vector to which the matrix is to be applied,
+-c                 m is the length of y,
+-c                 y is the product of the matrix and x,
+-c                 and p1, p2, p3, and p4 are user-specified parameters
+-c       p1 -- parameter to be passed to routine matvec
+-c       p2 -- parameter to be passed to routine matvec
+-c       p3 -- parameter to be passed to routine matvec
+-c       p4 -- parameter to be passed to routine matvec
+-c       krank -- rank of the SVD being constructed
+-c
+-c       output:
+-c       u -- matrix of orthonormal left singular vectors of a
+-c       v -- matrix of orthonormal right singular vectors of a
+-c       s -- array of singular values of a
+-c       ier -- 0 when the routine terminates successfully;
+-c              nonzero otherwise
+-c
+-c       work:
+-c       w -- must be at least (krank+1)*(2*m+4*n+10)+8*krank**2
+-c            complex*16 elements long
+-c
+-c       _N.B._: The algorithm used by this routine is randomized.
+-c
+-        implicit none
+-        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
+-     1          iwork,lwork,ier
+-        real*8 s(krank)
+-        complex*16 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
+-     1             w((krank+1)*(2*m+4*n+10)+8*krank**2)
+-        external matveca,matvec
+-c
+-c
+-c       Allocate memory in w.
+-c
+-        lw = 0
+-c
+-        ilist = lw+1
+-        llist = n
+-        lw = lw+llist
+-c
+-        iproj = lw+1
+-        lproj = krank*(n-krank)
+-        lw = lw+lproj
+-c
+-        icol = lw+1
+-        lcol = m*krank
+-        lw = lw+lcol
+-c
+-        iwork = lw+1
+-        lwork = (krank+1)*(m+3*n+10)+9*krank**2
+-        lw = lw+lwork
+-c
+-c
+-        call idzr_rsvd0(m,n,matveca,p1t,p2t,p3t,p4t,
+-     1                  matvec,p1,p2,p3,p4,krank,u,v,s,ier,
+-     2                  w(ilist),w(iproj),w(icol),w(iwork))
+-c
+-c
+-        return
+-        end
+-c
+-c
+-c
+-c
+-        subroutine idzr_rsvd0(m,n,matveca,p1t,p2t,p3t,p4t,
+-     1                        matvec,p1,p2,p3,p4,krank,u,v,s,ier,
+-     2                        list,proj,col,work)
+-c
+-c       routine idzr_rsvd serves as a memory wrapper
+-c       for the present routine (please see routine idzr_rsvd
+-c       for further documentation).
+-c
+-        implicit none
+-        integer m,n,krank,list(n),ier,k
+-        real*8 s(krank)
+-        complex*16 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
+-     1             proj(krank*(n-krank)),col(m*krank),
+-     2             work((krank+1)*(m+3*n+10)+9*krank**2)
+-        external matveca,matvec
+-c
+-c
+-c       ID a.
+-c
+-        call idzr_rid(m,n,matveca,p1t,p2t,p3t,p4t,krank,list,work)
+-c
+-c
+-c       Retrieve proj from work.
+-c
+-        do k = 1,krank*(n-krank)
+-          proj(k) = work(k)
+-        enddo ! k
+-c
+-c
+-c       Collect together the columns of a indexed by list into col.
+-c
+-        call idz_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,col,work)
+-c
+-c
+-c       Convert the ID to an SVD.
+-c
+-        call idz_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
+-c
+-c
+-        return
+-        end
+diff --git a/scipy/linalg/src/id_dist/src/prini.f b/scipy/linalg/src/id_dist/src/prini.f
+deleted file mode 100644
+index 679590d84..000000000
+--- a/scipy/linalg/src/id_dist/src/prini.f
++++ /dev/null
+@@ -1,113 +0,0 @@
+-C
+-C
+-C
+-C
+-        SUBROUTINE PRINI(IP1,IQ1)
+-        save
+-        CHARACTER *1 MES(1), AA(1)
+-        REAL *4 A(1)
+-        REAL *8 A2(1)
+-        REAL *8 A4(1)
+-        INTEGER *4 IA(1)
+-        INTEGER *2 IA2(1)
+-        IP=IP1
+-        IQ=IQ1
+-
+-        RETURN
+-  
+-C
+-C
+-C
+-C
+-C
+-        ENTRY PRIN(MES,A,N)
+-        CALL  MESSPR(MES,IP,IQ)
+-        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1200)(A(J),J=1,N)
+-        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1200)(A(J),J=1,N)
+- 1200 FORMAT(6(2X,E11.5))
+-         RETURN
+-C
+-C
+-C
+-C
+-        ENTRY PRIN2(MES,A2,N)
+-        CALL MESSPR(MES,IP,IQ)
+-        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1400)(A2(J),J=1,N)
+-        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1400)(A2(J),J=1,N)
+- 1400 FORMAT(6(2X,E11.5))
+-        RETURN
+-C
+-C
+-C
+-C
+-        ENTRY PRIN2_long(MES,A2,N)
+-        CALL MESSPR(MES,IP,IQ)
+-        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1450)(A2(J),J=1,N)
+-        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1450)(A2(J),J=1,N)
+- 1450 FORMAT(2(2X,E22.16))
+-        RETURN
+-C
+-C
+-C
+-C
+-        ENTRY PRINQ(MES,A4,N)
+-        CALL MESSPR(MES,IP,IQ)
+-        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1500)(A4(J),J=1,N)
+-        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1500)(A4(J),J=1,N)
+- 1500 FORMAT(6(2X,e11.5))
+-        RETURN
+-C
+-C
+-C
+-C
+-        ENTRY PRINF(MES,IA,N)
+-        CALL MESSPR(MES,IP,IQ)
+-        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1600)(IA(J),J=1,N)
+-        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1600)(IA(J),J=1,N)
+- 1600 FORMAT(10(1X,I7))
+-        RETURN
+-C
+-C
+-C
+-C
+-        ENTRY PRINF2(MES,IA2,N)
+-        CALL MESSPR(MES,IP,IQ)
+-        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1600)(IA2(J),J=1,N)
+-        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1600)(IA2(J),J=1,N)
+-        RETURN
+-C
+-C
+-C
+-C
+-        ENTRY PRINA(MES,AA,N)
+-        CALL MESSPR(MES,IP,IQ)
+- 2000 FORMAT(1X,80A1)
+-        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,2000)(AA(J),J=1,N)
+-        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,2000)(AA(J),J=1,N)
+-        RETURN
+-        END
+-c
+-c
+-c
+-c
+-c
+-        SUBROUTINE MESSPR(MES,IP,IQ)
+-        save
+-        CHARACTER *1 MES(1),AST
+-        DATA AST/'*'/
+-C
+-C         DETERMINE THE LENGTH OF THE MESSAGE
+-C
+-        I1=0
+-        DO 1400 I=1,10000
+-        IF(MES(I).EQ.AST) GOTO 1600
+-        I1=I
+- 1400 CONTINUE
+- 1600 CONTINUE
+-         IF ( (I1.NE.0) .AND. (IP.NE.0) )
+-     1     WRITE(IP,1800) (MES(I),I=1,I1)
+-         IF ( (I1.NE.0) .AND. (IQ.NE.0) )
+-     1     WRITE(IQ,1800) (MES(I),I=1,I1)
+- 1800 FORMAT(1X,80A1)
+-         RETURN
+-         END
+diff --git a/scipy/linalg/tests/test_interpolative.py b/scipy/linalg/tests/test_interpolative.py
+index ddc56f7c7..95b83dfad 100644
+--- a/scipy/linalg/tests/test_interpolative.py
++++ b/scipy/linalg/tests/test_interpolative.py
+@@ -1,4 +1,4 @@
+-#******************************************************************************
++#  ******************************************************************************
+ #   Copyright (C) 2013 Kenneth L. Ho
+ #   Redistribution and use in source and binary forms, with or without
+ #   modification, are permitted provided that the following conditions are met:
+@@ -24,7 +24,7 @@
+ #   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ #   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ #   POSSIBILITY OF SUCH DAMAGE.
+-#******************************************************************************
++#  ******************************************************************************
+ 
+ import scipy.linalg.interpolative as pymatrixid
+ import numpy as np
+@@ -36,8 +36,6 @@ from numpy.testing import (assert_, assert_allclose, assert_equal,
+                            assert_array_equal)
+ import pytest
+ from pytest import raises as assert_raises
+-import sys
+-_IS_32BIT = (sys.maxsize < 2**32)
+ 
+ 
+ @pytest.fixture()
+@@ -45,6 +43,12 @@ def eps():
+     yield 1e-12
+ 
+ 
++@pytest.fixture()
++def rng():
++    rng = np.random.default_rng(1718313768084012)
++    yield rng
++
++
+ @pytest.fixture(params=[np.float64, np.complex128])
+ def A(request):
+     # construct Hilbert matrix
+@@ -73,36 +77,32 @@ class TestInterpolativeDecomposition:
+     @pytest.mark.parametrize(
+         "rand,lin_op",
+         [(False, False), (True, False), (True, True)])
+-    def test_real_id_fixed_precision(self, A, L, eps, rand, lin_op):
+-        if _IS_32BIT and A.dtype == np.complex128 and rand:
+-            pytest.xfail("bug in external fortran code")
++    def test_real_id_fixed_precision(self, A, L, eps, rand, lin_op, rng):
+         # Test ID routines on a Hilbert matrix.
+         A_or_L = A if not lin_op else L
+ 
+-        k, idx, proj = pymatrixid.interp_decomp(A_or_L, eps, rand=rand)
++        k, idx, proj = pymatrixid.interp_decomp(A_or_L, eps, rand=rand, rng=rng)
+         B = pymatrixid.reconstruct_matrix_from_id(A[:, idx[:k]], idx, proj)
+         assert_allclose(A, B, rtol=eps, atol=1e-08)
+ 
+     @pytest.mark.parametrize(
+         "rand,lin_op",
+         [(False, False), (True, False), (True, True)])
+-    def test_real_id_fixed_rank(self, A, L, eps, rank, rand, lin_op):
+-        if _IS_32BIT and A.dtype == np.complex128 and rand:
+-            pytest.xfail("bug in external fortran code")
++    def test_real_id_fixed_rank(self, A, L, eps, rank, rand, lin_op, rng):
+         k = rank
+         A_or_L = A if not lin_op else L
+ 
+-        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand)
++        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand, rng=rng)
+         B = pymatrixid.reconstruct_matrix_from_id(A[:, idx[:k]], idx, proj)
+         assert_allclose(A, B, rtol=eps, atol=1e-08)
+ 
+     @pytest.mark.parametrize("rand,lin_op", [(False, False)])
+     def test_real_id_skel_and_interp_matrices(
+-            self, A, L, eps, rank, rand, lin_op):
++            self, A, L, eps, rank, rand, lin_op, rng):
+         k = rank
+         A_or_L = A if not lin_op else L
+ 
+-        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand)
++        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand, rng=rng)
+         P = pymatrixid.reconstruct_interp_matrix(idx, proj)
+         B = pymatrixid.reconstruct_skel_matrix(A, k, idx)
+         assert_allclose(B, A[:, idx[:k]], rtol=eps, atol=1e-08)
+@@ -111,25 +111,21 @@ class TestInterpolativeDecomposition:
+     @pytest.mark.parametrize(
+         "rand,lin_op",
+         [(False, False), (True, False), (True, True)])
+-    def test_svd_fixed_precison(self, A, L, eps, rand, lin_op):
+-        if _IS_32BIT and A.dtype == np.complex128 and rand:
+-            pytest.xfail("bug in external fortran code")
++    def test_svd_fixed_precision(self, A, L, eps, rand, lin_op, rng):
+         A_or_L = A if not lin_op else L
+ 
+-        U, S, V = pymatrixid.svd(A_or_L, eps, rand=rand)
++        U, S, V = pymatrixid.svd(A_or_L, eps, rand=rand, rng=rng)
+         B = U * S @ V.T.conj()
+         assert_allclose(A, B, rtol=eps, atol=1e-08)
+ 
+     @pytest.mark.parametrize(
+         "rand,lin_op",
+         [(False, False), (True, False), (True, True)])
+-    def test_svd_fixed_rank(self, A, L, eps, rank, rand, lin_op):
+-        if _IS_32BIT and A.dtype == np.complex128 and rand:
+-            pytest.xfail("bug in external fortran code")
++    def test_svd_fixed_rank(self, A, L, eps, rank, rand, lin_op, rng):
+         k = rank
+         A_or_L = A if not lin_op else L
+ 
+-        U, S, V = pymatrixid.svd(A_or_L, k, rand=rand)
++        U, S, V = pymatrixid.svd(A_or_L, k, rand=rand, rng=rng)
+         B = U * S @ V.T.conj()
+         assert_allclose(A, B, rtol=eps, atol=1e-08)
+ 
+@@ -141,59 +137,39 @@ class TestInterpolativeDecomposition:
+         B = U * S @ V.T.conj()
+         assert_allclose(A, B, rtol=eps, atol=1e-08)
+ 
+-    def test_estimate_spectral_norm(self, A):
++    def test_estimate_spectral_norm(self, A, rng):
+         s = svdvals(A)
+-        norm_2_est = pymatrixid.estimate_spectral_norm(A)
++        norm_2_est = pymatrixid.estimate_spectral_norm(A, rng=rng)
+         assert_allclose(norm_2_est, s[0], rtol=1e-6, atol=1e-8)
+ 
+-    def test_estimate_spectral_norm_diff(self, A):
++    def test_estimate_spectral_norm_diff(self, A, rng):
+         B = A.copy()
+         B[:, 0] *= 1.2
+         s = svdvals(A - B)
+-        norm_2_est = pymatrixid.estimate_spectral_norm_diff(A, B)
++        norm_2_est = pymatrixid.estimate_spectral_norm_diff(A, B, rng=rng)
+         assert_allclose(norm_2_est, s[0], rtol=1e-6, atol=1e-8)
+ 
+-    def test_rank_estimates_array(self, A):
++    def test_rank_estimates_array(self, A, rng):
+         B = np.array([[1, 1, 0], [0, 0, 1], [0, 0, 1]], dtype=A.dtype)
+ 
+         for M in [A, B]:
+             rank_tol = 1e-9
+             rank_np = np.linalg.matrix_rank(M, norm(M, 2) * rank_tol)
+-            rank_est = pymatrixid.estimate_rank(M, rank_tol)
++            rank_est = pymatrixid.estimate_rank(M, rank_tol, rng=rng)
+             assert_(rank_est >= rank_np)
+             assert_(rank_est <= rank_np + 10)
+ 
+-    def test_rank_estimates_lin_op(self, A):
++    def test_rank_estimates_lin_op(self, A, rng):
+         B = np.array([[1, 1, 0], [0, 0, 1], [0, 0, 1]], dtype=A.dtype)
+ 
+         for M in [A, B]:
+             ML = aslinearoperator(M)
+             rank_tol = 1e-9
+             rank_np = np.linalg.matrix_rank(M, norm(M, 2) * rank_tol)
+-            rank_est = pymatrixid.estimate_rank(ML, rank_tol)
++            rank_est = pymatrixid.estimate_rank(ML, rank_tol, rng=rng)
+             assert_(rank_est >= rank_np - 4)
+             assert_(rank_est <= rank_np + 4)
+ 
+-    def test_rand(self):
+-        pymatrixid.seed('default')
+-        assert_allclose(pymatrixid.rand(2), [0.8932059, 0.64500803],
+-                        rtol=1e-4, atol=1e-8)
+-
+-        pymatrixid.seed(1234)
+-        x1 = pymatrixid.rand(2)
+-        assert_allclose(x1, [0.7513823, 0.06861718], rtol=1e-4, atol=1e-8)
+-
+-        np.random.seed(1234)
+-        pymatrixid.seed()
+-        x2 = pymatrixid.rand(2)
+-
+-        np.random.seed(1234)
+-        pymatrixid.seed(np.random.rand(55))
+-        x3 = pymatrixid.rand(2)
+-
+-        assert_allclose(x1, x2)
+-        assert_allclose(x1, x3)
+-
+     def test_badcall(self):
+         A = hilbert(5).astype(np.float32)
+         with assert_raises(ValueError):
+@@ -228,8 +204,6 @@ class TestInterpolativeDecomposition:
+     @pytest.mark.parametrize("rand", [True, False])
+     @pytest.mark.parametrize("eps", [1, 0.1])
+     def test_bug_9793(self, dtype, rand, eps):
+-        if _IS_32BIT and dtype == np.complex128 and rand:
+-            pytest.xfail("bug in external fortran code")
+         A = np.array([[-1, -1, -1, 0, 0, 0],
+                       [0, 0, 0, 1, 1, 1],
+                       [1, 0, 0, 1, 0, 0],
+-- 
+2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch b/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
new file mode 100644
index 00000000..705d648d
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
@@ -0,0 +1,38 @@
+From c11745d763407d9a2bb195a21e2a8afaf7635248 Mon Sep 17 00:00:00 2001
+From: Hood Chatham 
+Date: Sat, 6 Jul 2024 22:38:55 +0200
+Subject: [PATCH 8/18] Mark mvndst functions recursive
+
+---
+ scipy/stats/mvndst.f | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/scipy/stats/mvndst.f b/scipy/stats/mvndst.f
+index 41afa7e74..5065a15ff 100644
+--- a/scipy/stats/mvndst.f
++++ b/scipy/stats/mvndst.f
+@@ -21,8 +21,8 @@
+ *          Pullman, WA 99164-3113
+ *          Email : alangenz@wsu.edu
+ *
+-      SUBROUTINE mvnun(d, n, lower, upper, means, covar, maxpts, 
+-     &                   abseps, releps, value, inform)
++      RECURSIVE SUBROUTINE mvnun(d, n, lower, upper, means, covar, 
++     &                   maxpts, abseps, releps, value, inform)
+ *  Parameters
+ *
+ *   d       integer, dimensionality of the data
+@@ -88,8 +88,8 @@
+       END 
+ 
+ 
+-      SUBROUTINE mvnun_weighted(d, n, lower, upper, means, weights,
+-     &                          covar, maxpts, abseps, releps, 
++      recursive SUBROUTINE mvnun_weighted(d, n, lower, upper, means, 
++     &                          weights, covar, maxpts, abseps, releps,
+      &                           value, inform)
+ *  Parameters
+ *
+-- 
+2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch b/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
new file mode 100644
index 00000000..0ca5929f
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
@@ -0,0 +1,111 @@
+From e4d1a570fa8bd4c710e10400822f60232e6408eb Mon Sep 17 00:00:00 2001
+From: Hood Chatham 
+Date: Sat, 6 Jul 2024 22:33:51 +0200
+Subject: [PATCH 9/18] Make sreorth recursive
+
+---
+ complex16/zreorth.F | 6 +++---
+ complex8/creorth.F  | 6 +++---
+ double/dreorth.F    | 6 +++---
+ single/sreorth.F    | 6 +++---
+ 4 files changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/scipy/sparse/linalg/_propack/PROPACK/complex16/zreorth.F b/scipy/sparse/linalg/_propack/PROPACK/complex16/zreorth.F
+index ca74f7a..c447a6a 100644
+--- a/scipy/sparse/linalg/_propack/PROPACK/complex16/zreorth.F
++++ b/scipy/sparse/linalg/_propack/PROPACK/complex16/zreorth.F
+@@ -2,8 +2,8 @@ c
+ c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
+ c
+ 
+-      subroutine zreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
+-     c     iflag)
++      recursive subroutine zreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
++     c  work, iflag)
+ c
+ c     Orthogonalize the N-vector VNEW against a subset of the columns of
+ c     the N-by-K matrix V(1:N,1:K) using iterated classical or modified
+@@ -103,7 +103,7 @@ c
+ c****************************************************************************
+ c
+ 
+-      subroutine zcgs(n,k,V,ldv,vnew,index,work)
++      recursive subroutine zcgs(n,k,V,ldv,vnew,index,work)
+ 
+ c     Block  Gram-Schmidt orthogonalization:
+ c     FOR i= 1:l
+diff --git a/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F b/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F
+index cd87247..e657a89 100644
+--- a/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F
++++ b/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F
+@@ -2,8 +2,8 @@ c
+ c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
+ c
+ 
+-      subroutine creorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
+-     c     iflag)
++      recursive subroutine creorth(n,k,V,ldv,vnew,normvnew,index,alpha,
++     c  work, iflag)
+ c
+ c     Orthogonalize the N-vector VNEW against a subset of the columns of
+ c     the N-by-K matrix V(1:N,1:K) using iterated classical or modified
+@@ -103,7 +103,7 @@ c
+ c****************************************************************************
+ c
+ 
+-      subroutine ccgs(n,k,V,ldv,vnew,index,work)
++      recursive subroutine ccgs(n,k,V,ldv,vnew,index,work)
+ 
+ c     Block  Gram-Schmidt orthogonalization:
+ c     FOR i= 1:l
+diff --git a/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F b/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F
+index 841208a..fec923e 100644
+--- a/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F
++++ b/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F
+@@ -2,8 +2,8 @@ c
+ c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
+ c
+ 
+-      subroutine dreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
+-     c     iflag)
++      recursive subroutine dreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
++     c  work, iflag)
+ c
+ c     Orthogonalize the N-vector VNEW against a subset of the columns of
+ c     the N-by-K matrix V(1:N,1:K) using iterated classical or modified
+@@ -103,7 +103,7 @@ c
+ c****************************************************************************
+ c
+ 
+-      subroutine dcgs(n,k,V,ldv,vnew,index,work)
++      recursive subroutine dcgs(n,k,V,ldv,vnew,index,work)
+ 
+ c     Block  Gram-Schmidt orthogonalization:
+ c     FOR i= 1:l
+diff --git a/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F b/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F
+index 644d404..61b6698 100644
+--- a/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F
++++ b/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F
+@@ -2,8 +2,8 @@ c
+ c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
+ c
+ 
+-      subroutine sreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
+-     c     iflag)
++      recursive subroutine sreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
++     c  work, iflag)
+ c
+ c     Orthogonalize the N-vector VNEW against a subset of the columns of
+ c     the N-by-K matrix V(1:N,1:K) using iterated classical or modified
+@@ -103,7 +103,7 @@ c
+ c****************************************************************************
+ c
+ 
+-      subroutine scgs(n,k,V,ldv,vnew,index,work)
++      recursive subroutine scgs(n,k,V,ldv,vnew,index,work)
+ 
+ c     Block  Gram-Schmidt orthogonalization:
+ c     FOR i= 1:l
+-- 
+2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch b/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
new file mode 100644
index 00000000..ad975ccd
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
@@ -0,0 +1,76 @@
+From ccbb0fa0884d567c6139eeed7dc2dc9f8db4db3a Mon Sep 17 00:00:00 2001
+From: ryanking13 
+Date: Sun, 28 Jul 2024 18:15:17 +0900
+Subject: [PATCH 10/18] Link openblas with modules that require f2c
+
+Some fortran modules require symbols from f2c, which is provided by
+openblas.
+This patch adds openblas as a dependency to the modules that require f2c
+symbols.
+
+Co-Developed-by: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
+---
+ scipy/integrate/meson.build | 2 +-
+ scipy/optimize/meson.build  | 6 +++---
+ scipy/stats/meson.build     | 2 +-
+ 3 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/scipy/integrate/meson.build b/scipy/integrate/meson.build
+index 23a715dd58..e5cd9ad4c8 100644
+--- a/scipy/integrate/meson.build
++++ b/scipy/integrate/meson.build
+@@ -154,7 +154,7 @@ py3.extension_module('_dop',
+   f2py_gen.process('dop.pyf'),
+   link_with: [dop_lib],
+   c_args: [Wno_unused_variable],
+-  dependencies: [fortranobject_dep],
++  dependencies: [lapack, fortranobject_dep],
+   link_args: version_link_args,
+   install: true,
+   link_language: 'fortran',
+diff --git a/scipy/optimize/meson.build b/scipy/optimize/meson.build
+index d6c20d3d53..d7f0284b5b 100644
+--- a/scipy/optimize/meson.build
++++ b/scipy/optimize/meson.build
+@@ -125,7 +125,7 @@ py3.extension_module('_cobyla',
+   c_args: [Wno_unused_variable],
+   fortran_args: fortran_ignore_warnings,
+   link_args: version_link_args,
+-  dependencies: [fortranobject_dep],
++  dependencies: [lapack, fortranobject_dep],
+   install: true,
+   link_language: 'fortran',
+   subdir: 'scipy/optimize'
+@@ -135,7 +135,7 @@ py3.extension_module('_minpack2',
+   [f2py_gen.process('minpack2/minpack2.pyf'), 'minpack2/dcsrch.f', 'minpack2/dcstep.f'],
+   fortran_args: fortran_ignore_warnings,
+   link_args: version_link_args,
+-  dependencies: [fortranobject_dep],
++  dependencies: [lapack, fortranobject_dep],
+   override_options: ['b_lto=false'],
+   install: true,
+   link_language: 'fortran',
+@@ -146,7 +146,7 @@ py3.extension_module('_slsqp',
+   [f2py_gen.process('slsqp/slsqp.pyf'), 'slsqp/slsqp_optmz.f'],
+   fortran_args: fortran_ignore_warnings,
+   link_args: version_link_args,
+-  dependencies: [fortranobject_dep],
++  dependencies: [lapack, fortranobject_dep],
+   install: true,
+   link_language: 'fortran',
+   subdir: 'scipy/optimize'
+diff --git a/scipy/stats/meson.build b/scipy/stats/meson.build
+index bb43e3b2e9..358279a93b 100644
+--- a/scipy/stats/meson.build
++++ b/scipy/stats/meson.build
+@@ -36,7 +36,7 @@ py3.extension_module('_mvn',
+   # Wno-surprising is to suppress a pointless warning with GCC 10-12
+   # (see GCC bug 98411: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98411)
+   fortran_args: [fortran_ignore_warnings, _fflag_Wno_surprising],
+-  dependencies: [fortranobject_dep],
++  dependencies: [lapack, fortranobject_dep],
+   link_args: version_link_args,
+   install: true,
+   link_language: 'fortran',
+-- 
+2.39.3 (Apple Git-146)
diff --git a/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch b/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
new file mode 100644
index 00000000..78272f58
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
@@ -0,0 +1,94 @@
+From b43a231f8326d6953929030131c3fb6b2cb163bd Mon Sep 17 00:00:00 2001
+From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
+Date: Wed, 15 May 2024 21:29:02 +0530
+Subject: [PATCH 11/18] Remove fpchec inline if-then-endif constructs
+
+This PR removes the single-line if-then-endif constructs in fpchec.f
+that were causing syntactical errors when compiling with f2c, possibly
+because fpchec uses some dated, punch-card FORTRAN syntax. It converts
+them to statements split over multiple lines.
+
+This patch has been upstreamed via https://github.com/scipy/scipy/pull/21365
+and it can be safely removed once SciPy v1.15.0 is released and is being
+integrated in Pyodide.
+
+---
+ scipy/interpolate/fitpack/fpchec.f | 42 +++++++++++++++++++++++-------
+ 1 file changed, 32 insertions(+), 10 deletions(-)
+
+diff --git a/scipy/interpolate/fitpack/fpchec.f b/scipy/interpolate/fitpack/fpchec.f
+index 75a58c40ec..215f38f31f 100644
+--- a/scipy/interpolate/fitpack/fpchec.f
++++ b/scipy/interpolate/fitpack/fpchec.f
+@@ -29,36 +29,58 @@ c  ..
+       nk2 = nk1+1
+       ier = 10
+ c  check condition no 1
+-      if(nk1.lt.k1 .or. nk1.gt.m)then; ier=10; go to 80; endif
++      if (nk1.lt.k1 .or. nk1.gt.m) then
++          ier = 10
++          go to 80
++      endif
+ c  check condition no 2
+       j = n
+       do 20 i=1,k
+-        if(t(i).gt.t(i+1))then; ier=20; go to 80; endif
+-        if(t(j).lt.t(j-1))then; ier=20; go to 80; endif
++        if (t(i) .gt. t(i+1)) then
++            ier = 20
++            go to 80
++        endif
++        if (t(j) .lt. t(j-1)) then
++            ier = 20
++            go to 80
++        endif
+         j = j-1
+   20  continue
+ c  check condition no 3
+       do 30 i=k2,nk2
+-        if(t(i).le.t(i-1))then; ier=30; go to 80; endif
++        if (t(i) .le. t(i-1)) then
++            ier = 30
++            go to 80
++        endif
+   30  continue
+ c  check condition no 4
+-      if(x(1).lt.t(k1) .or. x(m).gt.t(nk2))then; ier=40; go to 80;
++      if (x(1).lt.t(k1) .or. x(m).gt.t(nk2)) then
++          ier = 40
++          go to 80
+       endif
+ c  check condition no 5
+-      if(x(1).ge.t(k2) .or. x(m).le.t(nk1))then; ier=50; go to 80;
++      if (x(1).ge.t(k2) .or. x(m).le.t(nk1)) then
++          ier = 50
++          go to 80
+       endif
+       i = 1
+       l = k2
+       nk3 = nk1-1
+-      if(nk3.lt.2) go to 70
++      if (nk3 .lt. 2) go to 70
+       do 60 j=2,nk3
+         tj = t(j)
+         l = l+1
+         tl = t(l)
+   40    i = i+1
+-        if(i.ge.m)then; ier=50; go to 80; endif
+-        if(x(i).le.tj) go to 40
+-        if(x(i).ge.tl)then; ier=50; go to 80; endif
++        if (i .ge. m) then
++            ier = 50
++            go to 80
++        endif
++        if (x(i) .le. tj) go to 40
++        if (x(i) .ge. tl) then
++            ier = 50
++            go to 80
++        endif
+   60  continue
+   70  ier = 0
+   80  return
+-- 
+2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch b/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch
new file mode 100644
index 00000000..c4afc190
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch
@@ -0,0 +1,27 @@
+From 848c94e218e89d866978fbc883cbb2d919f56ce9 Mon Sep 17 00:00:00 2001
+From: Hood Chatham 
+Date: Wed, 31 Jul 2024 10:29:47 +0200
+Subject: [PATCH 12/18] Remove chla_transtype
+
+The signature should probably be `int chla_transtype(char* res, int *trans)`.
+This just deletes it entirely due to laziness.
+
+---
+ scipy/linalg/cython_lapack_signatures.txt | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/scipy/linalg/cython_lapack_signatures.txt b/scipy/linalg/cython_lapack_signatures.txt
+index 1f3dc226ab..28aa8b8c22 100644
+--- a/scipy/linalg/cython_lapack_signatures.txt
++++ b/scipy/linalg/cython_lapack_signatures.txt
+@@ -108,7 +108,6 @@ void chetrs(char *uplo, int *n, int *nrhs, c *a, int *lda, int *ipiv, c *b, int
+ void chetrs2(char *uplo, int *n, int *nrhs, c *a, int *lda, int *ipiv, c *b, int *ldb, c *work, int *info)
+ void chfrk(char *transr, char *uplo, char *trans, int *n, int *k, s *alpha, c *a, int *lda, s *beta, c *c)
+ void chgeqz(char *job, char *compq, char *compz, int *n, int *ilo, int *ihi, c *h, int *ldh, c *t, int *ldt, c *alpha, c *beta, c *q, int *ldq, c *z, int *ldz, c *work, int *lwork, s *rwork, int *info)
+-char chla_transtype(int *trans)
+ void chpcon(char *uplo, int *n, c *ap, int *ipiv, s *anorm, s *rcond, c *work, int *info)
+ void chpev(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, s *rwork, int *info)
+ void chpevd(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, int *lwork, s *rwork, int *lrwork, int *iwork, int *liwork, int *info)
+-- 
+2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch b/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch
new file mode 100644
index 00000000..c20be03f
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch
@@ -0,0 +1,25 @@
+From b5d05197de084ab3cab52241f163bae7519b6027 Mon Sep 17 00:00:00 2001
+From: Hood Chatham 
+Date: Wed, 31 Jul 2024 11:48:12 +0200
+Subject: [PATCH 13/18] Set wrapper return type to int
+
+---
+ scipy/linalg/_generate_pyx.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/scipy/linalg/_generate_pyx.py b/scipy/linalg/_generate_pyx.py
+index 8a00f5d279..aeb86e8926 100644
+--- a/scipy/linalg/_generate_pyx.py
++++ b/scipy/linalg/_generate_pyx.py
+@@ -520,7 +520,7 @@ def generate_decl_c(name, return_type, argnames, argtypes, accelerate):
+     if name in WRAPPED_FUNCS:
+         argnames = ['out'] + argnames
+         c_argtypes = [c_return_type] + c_argtypes
+-        c_return_type = 'void'
++        c_return_type = 'int'
+     blas_macro, blas_name = get_blas_macro_and_name(name, accelerate)
+     c_args = ', '.join(f'{t} *{n}' for t, n in zip(c_argtypes, argnames))
+     return f"{c_return_type} {blas_macro}({blas_name})({c_args});\n"
+-- 
+2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch b/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
new file mode 100644
index 00000000..b9e521f3
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
@@ -0,0 +1,51 @@
+From 59d3efdf9e55958c6a3651e8eda2a9d6fe48e192 Mon Sep 17 00:00:00 2001
+From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
+Date: Fri, 9 Aug 2024 19:00:41 +0530
+Subject: [PATCH 14/18] Skip svd_gesdd test
+
+This patch excludes a test for gesdd which was introduced in this PR:
+https://github.com/scipy/scipy/pull/20349. It is not useful for Pyodide
+since it is a memory-intensive test and it is not expected to pass in
+a WASM environment where allocating memory for large arrays is tricky.
+
+This patch has been upstreamed in https://github.com/scipy/scipy/pull/21349
+and it can be safely removed once SciPy v1.15.0 is released and is being
+integrated in Pyodide.
+
+---
+ scipy/linalg/tests/test_decomp.py | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/scipy/linalg/tests/test_decomp.py b/scipy/linalg/tests/test_decomp.py
+index b43016c027..cbd80252b1 100644
+--- a/scipy/linalg/tests/test_decomp.py
++++ b/scipy/linalg/tests/test_decomp.py
+@@ -1,5 +1,6 @@
+ import itertools
+ import platform
++import sys
+ 
+ import numpy as np
+ from numpy.testing import (assert_equal, assert_almost_equal,
+@@ -37,6 +38,8 @@ try:
+ except ImportError:
+     CONFIG = None
+ 
++IS_WASM = (sys.platform == "emscripten" or platform.machine() in ["wasm32", "wasm64"])
++
+ 
+ def _random_hermitian_matrix(n, posdef=False, dtype=float):
+     "Generate random sym/hermitian array of the given size n"
+@@ -1179,6 +1182,9 @@ class TestSVD_GESVD(TestSVD_GESDD):
+     lapack_driver = 'gesvd'
+ 
+ 
++# Allocating an array of such a size leads to _ArrayMemoryError(s)
++# since the maximum memory that can be in 32-bit (WASM) is 4GB
++@pytest.mark.skipif(IS_WASM, reason="out of memory in WASM")
+ @pytest.mark.fail_slow(5)
+ def test_svd_gesdd_nofegfault():
+     # svd(a) with {U,VT}.size > INT_MAX does not segfault
+-- 
+2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch b/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
new file mode 100644
index 00000000..a80ca320
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
@@ -0,0 +1,304 @@
+From 9b670bd5330bd7834d157a9ec3087a97b71d6516 Mon Sep 17 00:00:00 2001
+From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
+Date: Fri, 16 Aug 2024 22:59:26 +0530
+Subject: [PATCH 15/18] Remove f2py generators
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This patch reverts changes made in d85ba6b910ea9040b6a72bdc4ea87d151118f41d
+and is applied at the end, after the rest of the patches – the order is important.
+
+It removes the f2py generator and replaces it with custom targets mapping to
+f2py-generated wrappers. This is done to avoid the need for the f2py executable
+to be present in the environment where SciPy is built. Instead, the Python
+executable is used to run f2py as a module which is useful where f2py is not
+present on PATH.
+
+---
+ scipy/integrate/meson.build              | 32 +++++++++++++++++++++---
+ scipy/interpolate/meson.build            |  8 +++++-
+ scipy/io/meson.build                     |  8 +++++-
+ scipy/meson.build                        | 24 ------------------
+ scipy/optimize/meson.build               | 30 +++++++++++++++++++---
+ scipy/sparse/linalg/_propack/meson.build |  8 +++++-
+ scipy/stats/meson.build                  |  8 +++++-
+ tools/generate_f2pymod.py                |  3 ++-
+ 8 files changed, 85 insertions(+), 36 deletions(-)
+
+diff --git a/scipy/integrate/meson.build b/scipy/integrate/meson.build
+index cfaa927139..44c63fa526 100644
+--- a/scipy/integrate/meson.build
++++ b/scipy/integrate/meson.build
+@@ -128,8 +128,14 @@ py3.extension_module('_odepack',
+   subdir: 'scipy/integrate'
+ )
+ 
++vode_module = custom_target('vode_module',
++  output: ['_vode-f2pywrappers.f', '_vodemodule.c'],
++  input: 'vode.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ py3.extension_module('_vode',
+-  f2py_gen.process('vode.pyf'),
++  vode_module,
+   link_with: [vode_lib],
+   c_args: [Wno_unused_variable],
+   link_args: version_link_args,
+@@ -139,8 +145,14 @@ py3.extension_module('_vode',
+   subdir: 'scipy/integrate'
+ )
+ 
++lsoda_module = custom_target('lsoda_module',
++  output: ['_lsoda-f2pywrappers.f', '_lsodamodule.c'],
++  input: 'lsoda.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ py3.extension_module('_lsoda',
+-  f2py_gen.process('lsoda.pyf'),
++  lsoda_module,
+   link_with: [lsoda_lib, mach_lib],
+   c_args: [Wno_unused_variable],
+   dependencies: [lapack_dep, fortranobject_dep],
+@@ -150,8 +162,14 @@ py3.extension_module('_lsoda',
+   subdir: 'scipy/integrate'
+ )
+ 
++_dop_module = custom_target('_dop_module',
++  output: ['_dop-f2pywrappers.f', '_dopmodule.c'],
++  input: 'dop.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ py3.extension_module('_dop',
+-  f2py_gen.process('dop.pyf'),
++  _dop_module,
+   link_with: [dop_lib],
+   c_args: [Wno_unused_variable],
+   dependencies: [lapack, fortranobject_dep],
+@@ -169,8 +187,14 @@ py3.extension_module('_test_multivariate',
+   install_tag: 'tests'
+ )
+ 
++_test_odeint_banded_module = custom_target('_test_odeint_banded_module',
++  output: ['_test_odeint_bandedmodule.c', '_test_odeint_banded-f2pywrappers.f'],
++  input: 'tests/test_odeint_banded.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ py3.extension_module('_test_odeint_banded',
+-  ['tests/banded5x5.f', f2py_gen.process('tests/test_odeint_banded.pyf')],
++  ['tests/banded5x5.f', _test_odeint_banded_module],
+   link_with: [lsoda_lib, mach_lib],
+   fortran_args: _fflag_Wno_unused_dummy_argument,
+   link_args: version_link_args,
+diff --git a/scipy/interpolate/meson.build b/scipy/interpolate/meson.build
+index 69ec25f6af..38dd2a8cc3 100644
+--- a/scipy/interpolate/meson.build
++++ b/scipy/interpolate/meson.build
+@@ -143,9 +143,15 @@ py3.extension_module('_fitpack',
+   subdir: 'scipy/interpolate'
+ )
+ 
++dfitpack_module = custom_target('dfitpack_module',
++  output: ['_dfitpack-f2pywrappers.f', '_dfitpackmodule.c'],
++  input: 'src/dfitpack.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ # TODO: Add flags for 64 bit ints
+ py3.extension_module('_dfitpack',
+-  f2py_gen.process('src/dfitpack.pyf'),
++  dfitpack_module,
+   c_args: [Wno_unused_variable],
+   link_args: version_link_args,
+   dependencies: [lapack_dep, fortranobject_dep],
+diff --git a/scipy/io/meson.build b/scipy/io/meson.build
+index 60f71c6968..89a9cf69ba 100644
+--- a/scipy/io/meson.build
++++ b/scipy/io/meson.build
+@@ -1,6 +1,12 @@
++_test_fortran_module = custom_target('_test_fortran_module',
++  output: ['_test_fortranmodule.c'],
++  input: 'test_fortran.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ py3.extension_module('_test_fortran',
+   [
+-    f2py_gen.process('test_fortran.pyf'),
++    _test_fortran_module,
+     '_test_fortran.f'
+   ],
+   c_args: [Wno_unused_variable],
+diff --git a/scipy/meson.build b/scipy/meson.build
+index a0857848a2..ff47bde52e 100644
+--- a/scipy/meson.build
++++ b/scipy/meson.build
+@@ -144,30 +144,6 @@ fortranobject_dep = declare_dependency(
+   compile_args: _f2py_c_args,
+ )
+ 
+-f2py = find_program('f2py')
+-# It should be quite rare for the `f2py` executable to not be the one from
+-# `numpy` installed in the Python env we are building for (unless we are
+-# cross-compiling). If it is from a different env, that is still fine as long
+-# as it's not too old. We are only using f2py as a code generator, and the
+-# output is not dependent on platform or Python version (see gh-20612 for more
+-# details).
+-# This should be robust enough. If not, we can make this more complex, using
+-# a fallback to `python -m f2py` rather than erroring out.
+-f2py_version = run_command([f2py, '-v'], check: true).stdout().strip()
+-if f2py_version.version_compare('<'+min_numpy_version)
+-  error(f'Found f2py executable is too old: @f2py_version@')
+-endif
+-
+-# Note: this generato cannot handle:
+-# 1. `.pyf.src` files, because `@BASENAME@` will still include .pyf
+-# 2. targets with #include's (due to no `depend_files` - see feature request
+-#    at meson#8295)
+-f2py_gen = generator(generate_f2pymod,
+-  arguments : ['@INPUT@', '-o', '@BUILD_DIR@'],
+-  output : ['_@BASENAME@module.c', '_@BASENAME@-f2pywrappers.f'],
+-)
+-
+-
+ # TODO: 64-bit BLAS and LAPACK
+ #
+ # Note that this works as long as BLAS and LAPACK are detected properly via
+diff --git a/scipy/optimize/meson.build b/scipy/optimize/meson.build
+index 50d62ef68b..6cef85027a 100644
+--- a/scipy/optimize/meson.build
++++ b/scipy/optimize/meson.build
+@@ -92,12 +92,18 @@ py3.extension_module('_zeros',
+   subdir: 'scipy/optimize'
+ )
+ 
++lbfgsb_module = custom_target('lbfgsb_module',
++  output: ['_lbfgsb-f2pywrappers.f', '_lbfgsbmodule.c'],
++  input: 'lbfgsb_src/lbfgsb.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ py3.extension_module('_lbfgsb',
+   [
+     'lbfgsb_src/lbfgsb.f',
+     'lbfgsb_src/linpack.f',
+     'lbfgsb_src/timer.f',
+-    f2py_gen.process('lbfgsb_src/lbfgsb.pyf'),
++    lbfgsb_module,
+   ],
+   fortran_args: fortran_ignore_warnings,
+   link_args: version_link_args,
+@@ -120,6 +126,12 @@ py3.extension_module('_moduleTNC',
+   subdir: 'scipy/optimize'
+ )
+ 
++cobyla_module = custom_target('cobyla_module',
++  output: ['_cobylamodule.c'],
++  input: 'cobyla/cobyla.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ py3.extension_module('_cobyla',
+-  [f2py_gen.process('cobyla/cobyla.pyf'), 'cobyla/cobyla2.f', 'cobyla/trstlp.f'],
++  [cobyla_module, 'cobyla/cobyla2.f', 'cobyla/trstlp.f'],
+   c_args: [Wno_unused_variable],
+@@ -131,8 +143,14 @@ py3.extension_module('_cobyla',
+   subdir: 'scipy/optimize'
+ )
+ 
++minpack2_module = custom_target('minpack2_module',
++  output: ['_minpack2module.c'],
++  input: 'minpack2/minpack2.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ py3.extension_module('_minpack2',
+-  [f2py_gen.process('minpack2/minpack2.pyf'), 'minpack2/dcsrch.f', 'minpack2/dcstep.f'],
++  [minpack2_module, 'minpack2/dcsrch.f', 'minpack2/dcstep.f'],
+   fortran_args: fortran_ignore_warnings,
+   link_args: version_link_args,
+   dependencies: [lapack, fortranobject_dep],
+@@ -142,8 +160,14 @@ py3.extension_module('_minpack2',
+   subdir: 'scipy/optimize'
+ )
+ 
++slsqp_module = custom_target('slsqp_module',
++  output: ['_slsqpmodule.c'],
++  input: 'slsqp/slsqp.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ py3.extension_module('_slsqp',
+-  [f2py_gen.process('slsqp/slsqp.pyf'), 'slsqp/slsqp_optmz.f'],
++  [slsqp_module, 'slsqp/slsqp_optmz.f'],
+   fortran_args: fortran_ignore_warnings,
+   link_args: version_link_args,
+   dependencies: [fortranobject_dep],
+diff --git a/scipy/sparse/linalg/_propack/meson.build b/scipy/sparse/linalg/_propack/meson.build
+index 6714724958..df358df651 100644
+--- a/scipy/sparse/linalg/_propack/meson.build
++++ b/scipy/sparse/linalg/_propack/meson.build
+@@ -97,8 +97,14 @@ foreach ele: elements
+     gnu_symbol_visibility: 'hidden',
+   )
+ 
++  propack_module = custom_target('propack_module' + ele[0],
++    output: [ele[0] + '-f2pywrappers.f', ele[0] + 'module.c'],
++    input: ele[2],
++    command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++  )
++
+   propacklib = py3.extension_module(ele[0],
+-    f2py_gen.process(ele[2]),
++    propack_module,
+     link_with: propack_lib,
+     c_args: ['-U_OPENMP', _cpp_Wno_cpp],
+     fortran_args: _fflag_Wno_maybe_uninitialized,
+diff --git a/scipy/stats/meson.build b/scipy/stats/meson.build
+index 358279a93b..7c973b1cf3 100644
+--- a/scipy/stats/meson.build
++++ b/scipy/stats/meson.build
+@@ -31,8 +31,14 @@ py3.extension_module('_ansari_swilk_statistics',
+   subdir: 'scipy/stats'
+ )
+ 
++mvn_module = custom_target('mvn_module',
++  output: ['_mvn-f2pywrappers.f', '_mvnmodule.c'],
++  input: 'mvn.pyf',
++  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
++)
++
+ py3.extension_module('_mvn',
+-  [f2py_gen.process('mvn.pyf'), 'mvndst.f'],
++  [mvn_module, 'mvndst.f'],
+   # Wno-surprising is to suppress a pointless warning with GCC 10-12
+   # (see GCC bug 98411: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98411)
+   fortran_args: [fortran_ignore_warnings, _fflag_Wno_surprising],
+diff --git a/tools/generate_f2pymod.py b/tools/generate_f2pymod.py
+index b6bc02eb04..3da75c14d1 100644
+--- a/tools/generate_f2pymod.py
++++ b/tools/generate_f2pymod.py
+@@ -9,6 +9,7 @@ import argparse
+ import os
+ import re
+ import subprocess
++import sys
+ 
+ 
+ # START OF CODE VENDORED FROM `numpy.distutils.from_template`
+@@ -283,7 +284,7 @@ def main():
+ 
+     # Now invoke f2py to generate the C API module file
+     if args.infile.endswith(('.pyf.src', '.pyf')):
+-        p = subprocess.Popen(['f2py', fname_pyf,
++        p = subprocess.Popen([sys.executable, '-m', 'numpy.f2py', fname_pyf,
+                             '--build-dir', outdir_abs], #'--quiet'],
+                             stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+                             cwd=os.getcwd())
+-- 
+2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch b/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
new file mode 100644
index 00000000..9f45ad86
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
@@ -0,0 +1,28 @@
+From 9d93ca19f4ad0ca327964b6234316547d774b17f Mon Sep 17 00:00:00 2001
+From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
+Date: Sat, 17 Aug 2024 01:12:28 +0530
+Subject: [PATCH 16/18] Make `sf_error_state_lib` a static library
+
+wasm.ld does not support linkage with shared libraries. This patch
+changes `sf_error_state_lib` to a static one.
+
+---
+ scipy/special/meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/scipy/special/meson.build b/scipy/special/meson.build
+index 82b813ea85..24bee0a21c 100644
+--- a/scipy/special/meson.build
++++ b/scipy/special/meson.build
+@@ -33,7 +33,7 @@ else
+   scipy_import_dll_args = []
+ endif
+ 
+-sf_error_state_lib = shared_library('sf_error_state',
++sf_error_state_lib = static_library('sf_error_state',
+   ['sf_error_state.c'],
+   include_directories: ['../_lib', '../_build_utils/src'],
+   c_args: scipy_export_dll_args,
+-- 
+2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch b/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
new file mode 100644
index 00000000..56be63ec
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
@@ -0,0 +1,74 @@
+From e21f33695da3275ec81b5f94685f0e4ac92c9ad5 Mon Sep 17 00:00:00 2001
+From: Gyeongjae Choi 
+Date: Mon, 30 Oct 2023 14:35:04 +0000
+Subject: [PATCH 17/18] Remove test modules that fail to build
+
+These are tests and they have both void vs int return value problems and implicit
+function argument cast problems. Not worth fixing for tests.
+
+---
+ scipy/integrate/meson.build | 18 ------------------
+ scipy/io/meson.build        | 21 ---------------------
+ 2 files changed, 39 deletions(-)
+
+diff --git a/scipy/integrate/meson.build b/scipy/integrate/meson.build
+index ae9e2466e1..e11626db0d 100644
+--- a/scipy/integrate/meson.build
++++ b/scipy/integrate/meson.build
+@@ -187,24 +187,6 @@ py3.extension_module('_test_multivariate',
+   install_tag: 'tests'
+ )
+ 
+-_test_odeint_banded_module = custom_target('_test_odeint_banded_module',
+-  output: ['_test_odeint_bandedmodule.c', '_test_odeint_banded-f2pywrappers.f'],
+-  input: 'tests/test_odeint_banded.pyf',
+-  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
+-)
+-
+-py3.extension_module('_test_odeint_banded',
+-  ['tests/banded5x5.f', _test_odeint_banded_module],
+-  link_with: [lsoda_lib, mach_lib],
+-  fortran_args: _fflag_Wno_unused_dummy_argument,
+-  link_args: version_link_args,
+-  dependencies: [lapack_dep, fortranobject_dep],
+-  install: true,
+-  link_language: 'fortran',
+-  subdir: 'scipy/integrate',
+-  install_tag: 'tests'
+-)
+-
+ subdir('_ivp')
+ subdir('tests')
+ 
+diff --git a/scipy/io/meson.build b/scipy/io/meson.build
+index d6fc6dc749..af04022208 100644
+--- a/scipy/io/meson.build
++++ b/scipy/io/meson.build
+@@ -1,24 +1,3 @@
+-_test_fortran_module = custom_target('_test_fortran_module',
+-  output: ['_test_fortranmodule.c'],
+-  input: 'test_fortran.pyf',
+-  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
+-)
+-
+-py3.extension_module('_test_fortran',
+-  [
+-    _test_fortran_module,
+-    '_test_fortran.f'
+-  ],
+-  c_args: [Wno_unused_variable],
+-  fortran_args: fortran_ignore_warnings,
+-  link_args: version_link_args,
+-  dependencies: [lapack_dep, fortranobject_dep],
+-  install: true,
+-  link_language: 'fortran',
+-  subdir: 'scipy/io',
+-  install_tag: 'tests'
+-)
+-
+ py3.install_sources([
+     '__init__.py',
+     '_fortran.py',
+-- 
+2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch b/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
new file mode 100644
index 00000000..e2ffa67b
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
@@ -0,0 +1,38 @@
+From 8b06e7fef50327f84140cb09a3d9237e18b38a35 Mon Sep 17 00:00:00 2001
+From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
+Date: Thu, 5 Sep 2024 21:14:20 +0530
+Subject: [PATCH 18/18] Fix lapack larfg function signature
+
+This patch fixes the signature of the LAPACK routine larfg. Please
+see https://github.com/pyodide/pyodide/issues/3379 for more details.
+
+Co-authored-by: Ilhan Polat 
+Suggested-by: Hood Chatham 
+
+---
+ scipy/linalg/flapack_other.pyf.src | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/scipy/linalg/flapack_other.pyf.src b/scipy/linalg/flapack_other.pyf.src
+index 99d4886558..bf7256e605 100644
+--- a/scipy/linalg/flapack_other.pyf.src
++++ b/scipy/linalg/flapack_other.pyf.src
+@@ -2310,13 +2310,12 @@ function lange(norm,m,n,a,lda,work) result(n2)
+      dimension(m+1),intent(cache,hide) :: work
+ end function lange
+ 
+-subroutine larfg(n, alpha, x, incx, tau, lx)
++subroutine larfg(n, alpha, x, incx, tau)
+     integer intent(in), check(n>=1) :: n
+      intent(in,out) :: alpha
+-     intent(in,copy,out), dimension(lx) :: x
++     intent(in,copy,out), dimension(*), depend(n,incx), check(len(x) >= (n-2)*incx) :: x
+     integer intent(in), check(incx>0||incx<0) :: incx = 1
+      intent(out) :: tau
+-    integer intent(hide),depend(x,n,incx),check(lx > (n-2)*incx) :: lx = len(x)
+ end subroutine larfg
+ 
+ subroutine larf(side,m,n,v,incv,tau,c,ldc,work,lwork)
+-- 
+2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/scipy-conftest.py b/integration_tests/recipes/scipy/scipy-conftest.py
new file mode 100644
index 00000000..e7adcc8b
--- /dev/null
+++ b/integration_tests/recipes/scipy/scipy-conftest.py
@@ -0,0 +1,283 @@
+import re
+
+import pytest
+
+xfail = pytest.mark.xfail
+skip = pytest.mark.skip
+
+fp_exception_msg = (
+    "no floating point exceptions, "
+    "see https://github.com/numpy/numpy/pull/21895#issuecomment-1311525881"
+)
+process_msg = "no process support"
+thread_msg = "no thread support"
+todo_signature_mismatch_msg = "TODO signature mismatch"
+todo_memory_corruption_msgt = "TODO memory corruption"
+todo_genuine_difference_msg = "TODO genuine difference to be investigated"
+todo_fp_exception_msg = "TODO did not raise maybe no floating point exception support?"
+
+
+tests_to_mark = [
+    # scipy/_lib/tests
+    (
+        "test__threadsafety.py::test_parallel_threads",
+        xfail,
+        thread_msg,
+    ),
+    ("test__threadsafety.py::test_parallel_threads", xfail, thread_msg),
+    ("test__util.py::test_pool", xfail, process_msg),
+    ("test__util.py::test_mapwrapper_parallel", xfail, process_msg),
+    ("test_ccallback.py::test_threadsafety", xfail, thread_msg),
+    ("test_import_cycles.py::test_modules_importable", xfail, process_msg),
+    ("test_import_cycles.py::test_public_modules_importable", xfail, process_msg),
+    # scipy/datasets/tests
+    ("test_data.py::TestDatasets", xfail, "TODO datasets not working right now"),
+    # scipy/fft/tests
+    (
+        r"test_basic.py::TestFFT1D.test_dtypes\[float32-numpy\]",
+        xfail,
+        "TODO small floating point difference on the CI but not locally",
+    ),
+    ("test_basic.py::TestFFTThreadSafe", xfail, thread_msg),
+    ("test_basic.py::test_multiprocess", xfail, process_msg),
+    ("test_fft_function.py::test_fft_function", xfail, process_msg),
+    ("test_multithreading.py::test_threaded_same", xfail, thread_msg),
+    (
+        "test_multithreading.py::test_mixed_threads_processes",
+        xfail,
+        thread_msg,
+    ),
+    # scipy/integrate tests
+    ("test__quad_vec.py::test_quad_vec_pool", xfail, process_msg),
+    (
+        "test_quadpack.py.+TestCtypesQuad.test_ctypes.*",
+        xfail,
+        "Test relying on finding libm.so shared library",
+    ),
+    (
+        "test_quadrature.py.+TestQMCQuad.test_basic",
+        xfail,
+        todo_genuine_difference_msg,
+    ),
+    (
+        "test_quadrature.py.+TestQMCQuad.test_sign",
+        xfail,
+        todo_genuine_difference_msg,
+    ),
+    # scipy/interpolate
+    (
+        "test_fitpack.+test_kink",
+        xfail,
+        "TODO error not raised, maybe due to no floating point exception?",
+    ),
+    # scipy/io
+    (
+        "test_mmio.py::.+fast_matrix_market",
+        xfail,
+        thread_msg,
+    ),
+    (
+        "test_mmio.py::TestMMIOCoordinate.test_precision",
+        xfail,
+        thread_msg,
+    ),
+    (
+        "test_paths.py::TestPaths.test_mmio_(read|write)",
+        xfail,
+        thread_msg,
+    ),
+    # scipy/linalg tests
+    ("test_blas.+test_complex_dotu", skip, todo_signature_mismatch_msg),
+    ("test_cython_blas.+complex", skip, todo_signature_mismatch_msg),
+    ("test_lapack.py.+larfg_larf", skip, todo_signature_mismatch_msg),
+    # scipy/ndimage/tests
+    ("test_filters.py::TestThreading", xfail, thread_msg),
+    # scipy/optimize/tests
+    (
+        "test__differential_evolution.py::"
+        "TestDifferentialEvolutionSolver.test_immediate_updating",
+        xfail,
+        process_msg,
+    ),
+    (
+        "test__differential_evolution.py::TestDifferentialEvolutionSolver.test_parallel",
+        xfail,
+        process_msg,
+    ),
+    (
+        "test__shgo.py.+test_19_parallelization",
+        xfail,
+        process_msg,
+    ),
+    (
+        "test__shgo.py.+",
+        xfail,
+        "Test failing on 32bit (skipped on win32)",
+    ),
+    (
+        "test_linprog.py::TestLinprogSimplexNoPresolve.test_bounds_infeasible_2",
+        xfail,
+        "TODO no warnings emitted maybe due to no floating point exception?",
+    ),
+    ("test_minpack.py::TestFSolve.test_concurrent.+", xfail, process_msg),
+    ("test_minpack.py::TestLeastSq.test_concurrent+", xfail, process_msg),
+    ("test_optimize.py::test_cobyla_threadsafe", xfail, thread_msg),
+    ("test_optimize.py::TestBrute.test_workers", xfail, process_msg),
+    # scipy/signal/tests
+    (
+        "test_signaltools.py::TestMedFilt.test_medfilt2d_parallel",
+        xfail,
+        thread_msg,
+    ),
+    # scipy/sparse/tests
+    ("test_arpack.py::test_parallel_threads", xfail, thread_msg),
+    ("test_array_api.py::test_sparse_dense_divide", xfail, fp_exception_msg),
+    ("test_linsolve.py::TestSplu.test_threads_parallel", xfail, thread_msg),
+    ("test_propack", skip, todo_signature_mismatch_msg),
+    ("test_sparsetools.py::test_threads", xfail, thread_msg),
+    # scipy/sparse/csgraph/tests
+    ("test_shortest_path.py::test_gh_17782_segfault", xfail, thread_msg),
+    # scipy/sparse/linalg/tests
+    ("test_svds.py::Test_SVDS_PROPACK", skip, todo_signature_mismatch_msg),
+    # scipy/spatial/tests
+    (
+        "test_kdtree.py::test_query_ball_point_multithreading",
+        xfail,
+        thread_msg,
+    ),
+    ("test_kdtree.py::test_ckdtree_parallel", xfail, thread_msg),
+    # scipy/special/tests
+    (
+        "test_exponential_integrals.py::TestExp1.test_branch_cut",
+        xfail,
+        "TODO maybe float support since +0 and -0 difference",
+    ),
+    (
+        "test_round.py::test_add_round_(up|down)",
+        xfail,
+        "TODO small floating point difference, maybe due to lack of floating point "
+        "support for controlling rounding, see "
+        "https://github.com/WebAssembly/design/issues/1384",
+    ),
+    (
+        # This test is skipped for PyPy as well, maybe for a related reason?,
+        # see
+        # https://github.com/conda-forge/scipy-feedstock/pull/196#issuecomment-979317832
+        "test_distributions.py::TestBeta.test_boost_eval_issue_14606",
+        skip,
+        "TODO C++ exception that causes a Pyodide fatal error",
+    ),
+    # The following four tests do not raise the required
+    # 
+    (
+        "test_basic.py::test_error_raising",
+        xfail,
+        todo_fp_exception_msg,
+    ),
+    (
+        "test_sf_error.py::test_errstate_pyx_basic",
+        xfail,
+        todo_fp_exception_msg,
+    ),
+    (
+        "test_sf_error.py::test_errstate_cpp_scipy_special",
+        xfail,
+        todo_fp_exception_msg,
+    ),
+    (
+        "test_sf_error.py::test_errstate_cpp_alt_ufunc_machinery",
+        xfail,
+        todo_fp_exception_msg,
+    ),
+    (
+        "test_kdeoth.py::test_kde_[12]d",
+        xfail,
+        todo_genuine_difference_msg,
+    ),
+    (
+        "test_multivariate.py::TestMultivariateT.test_cdf_against_generic_integrators",
+        skip,
+        "TODO tplquad integration does not seem to converge",
+    ),
+    (
+        "test_multivariate.py::TestCovariance.test_mvn_with_covariance_cdf.+Precision-size1",
+        xfail,
+        "TODO small floating point difference 6e-7 relative diff instead of 1e-7",
+    ),
+    (
+        "test_multivariate.py::TestMultivariateNormal.test_logcdf_default_values",
+        xfail,
+        todo_genuine_difference_msg,
+    ),
+    (
+        "test_multivariate.py::TestMultivariateNormal.test_broadcasting",
+        xfail,
+        todo_genuine_difference_msg,
+    ),
+    (
+        "test_multivariate.py::TestMultivariateNormal.test_normal_1D",
+        xfail,
+        todo_genuine_difference_msg,
+    ),
+    (
+        "test_multivariate.py::TestMultivariateNormal.test_R_values",
+        xfail,
+        todo_genuine_difference_msg,
+    ),
+    (
+        "test_multivariate.py::TestMultivariateNormal.test_cdf_with_lower_limit",
+        xfail,
+        todo_genuine_difference_msg,
+    ),
+    (
+        "test_multivariate.py::TestMultivariateT.test_cdf_against_multivariate_normal",
+        xfail,
+        todo_genuine_difference_msg,
+    ),
+    ("test_qmc.py::TestVDC.test_van_der_corput", xfail, thread_msg),
+    ("test_qmc.py::TestHalton.test_workers", xfail, thread_msg),
+    ("test_qmc.py::TestUtils.test_discrepancy_parallel", xfail, thread_msg),
+    (
+        "test_qmc.py::TestMultivariateNormalQMC.test_validations",
+        xfail,
+        todo_fp_exception_msg,
+    ),
+    (
+        "test_qmc.py::TestMultivariateNormalQMC.test_MultivariateNormalQMCDegenerate",
+        xfail,
+        todo_genuine_difference_msg,
+    ),
+    ("test_sampling.py::test_threading_behaviour", xfail, thread_msg),
+    ("test_stats.py::TestMGCStat.test_workers", xfail, process_msg),
+    (
+        "test_stats.py::TestKSTwoSamples.testLargeBoth",
+        skip,
+        "TODO test taking > 5 minutes after scipy 1.10.1 update",
+    ),
+    (
+        "test_stats.py::TestKSTwoSamples.test_some_code_paths",
+        xfail,
+        todo_fp_exception_msg,
+    ),
+    (
+        "test_stats.py::TestGeometricStandardDeviation.test_raises_value_error",
+        xfail,
+        todo_fp_exception_msg,
+    ),
+    (
+        "test_stats.py::TestBrunnerMunzel.test_brunnermunzel_normal_dist",
+        xfail,
+        fp_exception_msg,
+    ),
+]
+
+
+def pytest_collection_modifyitems(config, items):
+    for item in items:
+        path, line, name = item.reportinfo()
+        path = str(path)
+        full_name = f"{path}::{name}"
+        for pattern, mark, reason in tests_to_mark:
+            if re.search(pattern, full_name):
+                # print(full_name)
+                item.add_marker(mark(reason=reason))
diff --git a/integration_tests/recipes/scipy/scipy-pytest.js b/integration_tests/recipes/scipy/scipy-pytest.js
new file mode 100644
index 00000000..6c3e54e5
--- /dev/null
+++ b/integration_tests/recipes/scipy/scipy-pytest.js
@@ -0,0 +1,84 @@
+const { opendir } = require("node:fs/promises");
+const { loadPyodide } = require("pyodide");
+
+async function main() {
+  let exit_code = 0;
+  try {
+    global.pyodide = await loadPyodide();
+    let pyodide = global.pyodide;
+    const FS = pyodide.FS;
+    const NODEFS = FS.filesystems.NODEFS;
+
+    let mountDir = "/mnt";
+    pyodide.FS.mkdir(mountDir);
+    pyodide.FS.mount(pyodide.FS.filesystems.NODEFS, { root: "." }, mountDir);
+
+    // Copy pytest-specific files dir if they exist
+    await pyodide.runPythonAsync(`
+       import shutil
+       import os
+
+       pytest_filenames = ["/mnt/conftest.py", "/mnt/pytest.ini"]
+
+       for filename in pytest_filenames:
+           if os.path.exists(filename):
+               shutil.copy(filename, ".")
+
+       conftest_filename = "/mnt/conftest.py"
+       if os.path.exists(conftest_filename):
+           shutil.copy(conftest_filename, ".")
+    `);
+
+    await pyodide.loadPackage(["micropip"]);
+    await pyodide.runPythonAsync(`
+       import micropip
+
+       await micropip.install('scipy')
+
+       try:
+           await micropip.install('scipy-tests')
+       except ValueError:
+           print('Hoping scipy tests are included in the scipy wheel')
+
+       pkg_list = micropip.list()
+       print(pkg_list)
+    `);
+
+    // XXX: some Fortran test modules are removed in Pyodide through a patch
+    // https://github.com/pyodide/pyodide/blob/main/packages/scipy/patches/0008-Remove-test-modules-that-fails-to-build.patch
+    // In order to avoid import errors during test discovery, we delete the
+    // problematic files. There seems to be no simpler way to do this with
+    // pytest, in particular --ignore-glob still imports the ignored file for
+    // some reason.
+    await pyodide.runPythonAsync(`
+      from pathlib import Path
+
+      import scipy.io.tests
+      path = Path(scipy.io.tests.__file__).parent / "test_fortran.py"
+      os.unlink(path)
+
+      import scipy.integrate.tests
+      path = Path(scipy.integrate.tests.__file__).parent / "test_odeint_jac.py"
+      os.unlink(path)
+    `);
+
+    await pyodide.runPythonAsync(
+      "import micropip; micropip.install(['pytest', 'hypothesis', 'pooch', 'lzma'])",
+    );
+    let pytest = pyodide.pyimport("pytest");
+    let args = process.argv.slice(2);
+    console.log("pytest args:", args);
+    exit_code = pytest.main(pyodide.toPy(args));
+  } catch (e) {
+    console.error(e);
+    // Arbitrary exit code here. I have seen this code reached instead of a
+    // Pyodide fatal error sometimes (I guess kind of similar to a random
+    // Python error). When there is a Pyodide fatal error we don't end up here
+    // somehow, and the exit code is 7
+    exit_code = 66;
+  } finally {
+    process.exit(exit_code);
+  }
+}
+
+main();
diff --git a/integration_tests/recipes/scipy/test_scipy.py b/integration_tests/recipes/scipy/test_scipy.py
new file mode 100644
index 00000000..ebd09bed
--- /dev/null
+++ b/integration_tests/recipes/scipy/test_scipy.py
@@ -0,0 +1,206 @@
+import pytest
+from pytest_pyodide import run_in_pyodide
+
+
+@pytest.mark.driver_timeout(40)
+@run_in_pyodide(packages=["scipy"])
+def test_scipy_linalg(selenium):
+    import numpy as np
+    import scipy.linalg
+    from numpy.testing import assert_allclose
+
+    N = 10
+    X = np.random.RandomState(42).rand(N, N)
+
+    X_inv = scipy.linalg.inv(X)
+
+    res = X.dot(X_inv)
+
+    assert_allclose(res, np.identity(N), rtol=1e-07, atol=1e-9)
+
+
+@pytest.mark.driver_timeout(40)
+@run_in_pyodide(packages=["scipy"])
+def test_brentq(selenium):
+    from scipy.optimize import brentq
+
+    brentq(lambda x: x, -1, 1)
+
+
+@pytest.mark.driver_timeout(40)
+@run_in_pyodide(packages=["scipy"])
+def test_dlamch(selenium):
+    from scipy.linalg import lapack
+
+    lapack.dlamch("Epsilon-Machine")
+
+
+@pytest.mark.driver_timeout(40)
+@run_in_pyodide(packages=["scipy"])
+def test_binom_ppf(selenium):
+    from scipy.stats import binom
+
+    assert binom.ppf(0.9, 1000, 0.1) == 112
+
+
+@pytest.mark.skip_pyproxy_check
+@pytest.mark.driver_timeout(40)
+@run_in_pyodide(packages=["pytest", "scipy-tests", "micropip"])
+async def test_scipy_pytest(selenium):
+    import pytest
+
+    import micropip
+
+    await micropip.install("hypothesis")
+
+    def runtest(module, filter):
+        result = pytest.main(
+            [
+                "--pyargs",
+                f"scipy.{module}",
+                "--continue-on-collection-errors",
+                "-vv",
+                "-k",
+                filter,
+            ]
+        )
+        assert result == 0
+
+    runtest("odr", "explicit")
+    runtest("stats.tests.test_multivariate", "haar")
+
+    # function signature mismatch with PROPACK, works with LOBPCG and ARPACK.
+    # Restore this when updating scipy
+    # runtest("sparse.linalg._eigen", "test_svds_parameter_k_which")
+    runtest(
+        "sparse.linalg._eigen.tests.test_svds",
+        "(not Test_SVDS_PROPACK) and test_svds_parameter_k_which",
+    )
+
+
+@pytest.mark.driver_timeout(40)
+@run_in_pyodide(packages=["scipy"])
+def test_cpp_exceptions(selenium):
+    import numpy as np
+    import pytest
+    from scipy.spatial.distance import cdist
+
+    out = np.ones((2, 2))
+    arr = np.array([[1, 2]])
+
+    with pytest.raises(ValueError, match="Output array has incorrect shape"):
+        cdist(arr, arr, out=out)
+    from scipy.sparse._sparsetools import test_throw_error
+
+    with pytest.raises(MemoryError):
+        test_throw_error()
+    from scipy.signal import lombscargle
+
+    with pytest.raises(ValueError):
+        lombscargle(x=[1], y=[1, 2], freqs=[1, 2, 3])
+
+
+# Regression test for LAPACK larfg signature mismatch
+# https://github.com/pyodide/pyodide/issues/3379
+@pytest.mark.driver_timeout(40)
+@run_in_pyodide(packages=["scipy", "numpy"])
+def test_lapack_larfg(selenium):
+    import numpy as np
+    from scipy.linalg.lapack import get_lapack_funcs
+
+    a = np.arange(16).reshape(4, 4)
+    a = a.T.dot(a)
+
+    (larfg,) = get_lapack_funcs(["larfg"], dtype="float64")
+    alpha, x, tau = larfg(a.shape[0] - 1, a[1, 0], a[2:, 0])
+    return (alpha, x, tau) is not None
+
+
+@pytest.mark.driver_timeout(40)
+@run_in_pyodide(packages=["scipy"])
+def test_logm(selenium_standalone):
+    import numpy as np
+    from numpy import eye, random
+    from scipy.linalg import logm
+
+    random.seed(1234)
+    dtype = np.float64
+    n = 2
+    scale = 1e-4
+    A = (eye(n) + random.rand(n, n) * scale).astype(dtype)
+    logm(A)
+
+
+@pytest.mark.driver_timeout(40)
+@run_in_pyodide(packages=["scipy"])
+def test_dblquad(selenium):
+    import scipy.integrate
+
+    unit_square_area = scipy.integrate.dblquad(
+        lambda y, x: 1, 0, 1, lambda x: 0, lambda x: 1
+    )
+    assert (
+        abs(unit_square_area[0] - 1) < unit_square_area[1]
+    ), f"Unit square area calculated using scipy.integrate.dblquad of {unit_square_area[0]} (+- {unit_square_area[0]}) is too far from 1.0"
+
+
+import shutil
+import subprocess
+from contextlib import contextmanager
+from pathlib import Path
+from typing import TYPE_CHECKING, Any
+
+
+def check_emscripten():
+    if not shutil.which("emcc"):
+        pytest.skip("Needs Emscripten")
+
+
+@contextmanager
+def venv_ctxmgr(path):
+    check_emscripten()
+
+    if TYPE_CHECKING:
+        create_pyodide_venv: Any = None
+    else:
+        from pyodide_build.out_of_tree.venv import create_pyodide_venv
+
+    create_pyodide_venv(path)
+    try:
+        yield path
+    finally:
+        shutil.rmtree(path, ignore_errors=True)
+
+
+@pytest.fixture(scope="module")
+def venv(runtime):
+    if runtime != "node":
+        pytest.xfail("node only")
+    check_emscripten()
+    path = Path(".venv-pyodide-tmp-test")
+    with venv_ctxmgr(path) as venv:
+        yield venv
+
+
+def install_pkg(venv, pkgname):
+    return subprocess.run(
+        [
+            venv / "bin/pip",
+            "install",
+            pkgname,
+            "--disable-pip-version-check",
+        ],
+        capture_output=True,
+        encoding="utf8",
+    )
+
+
+def test_cmdline_runner(selenium, venv):
+    result = install_pkg(venv, "scipy")
+    assert result.returncode == 0
+    result = subprocess.run(
+        [venv / "bin/python", Path(__file__).parent / "cmdline_test_file.py"]
+    )
+    print(result.stdout)
+    print(result.stderr)
+    assert result.returncode == 0

From a18357d48f35a5fdea7ec82a03575adec5addb1f Mon Sep 17 00:00:00 2001
From: "pre-commit-ci[bot]"
 <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Date: Tue, 15 Oct 2024 11:54:03 +0000
Subject: [PATCH 11/71] [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci
---
 .../recipes/libf2c/extras/make.inc            | 115 ++++------
 .../libf2c/patches/0001-fix-arith.h.patch     |   5 +-
 .../patches/0002-fix-f2clibs-build.patch      |   3 +-
 .../0003-remove-redundant-symbols.patch       |   9 +-
 .../patches/0004-correct-return-types.patch   |   9 +-
 ...5-Remove-symbols-defined-in-OpenBLAS.patch |   3 +-
 .../patches/0006-adjust-ld-ar-ranlib.patch    |  14 +-
 .../0001-Add-Wno-return-type-flag.patch       |   5 +-
 ...ray-signature-with-scipy-expectation.patch |   5 +-
 ...-Fix-dstevr-in-special-lapack_defs.h.patch |   5 +-
 .../scipy/patches/0002-int-to-string.patch    |   3 +-
 .../scipy/patches/0003-gemm_-no-const.patch   |  19 +-
 .../patches/0004-make-int-return-values.patch |  77 ++++---
 .../scipy/patches/0005-Fix-fitpack.patch      |   5 +-
 .../scipy/patches/0006-Fix-gees-calls.patch   |  15 +-
 ...-linalg-Remove-id_dist-Fortran-files.patch | 201 +++++++++---------
 ...0008-Mark-mvndst-functions-recursive.patch |  17 +-
 .../patches/0009-Make-sreorth-recursive.patch |  27 ++-
 ...enblas-with-modules-that-require-f2c.patch |   2 +-
 ...chec-inline-if-then-endif-constructs.patch |   3 +-
 .../patches/0012-Remove-chla_transtype.patch  |   3 +-
 .../0013-Set-wrapper-return-type-to-int.patch |   3 +-
 .../patches/0014-Skip-svd_gesdd-test.patch    |  13 +-
 .../patches/0015-Remove-f2py-generators.patch |  33 ++-
 ...-sf_error_state_lib-a-static-library.patch |   5 +-
 ...move-test-modules-that-fail-to-build.patch |   7 +-
 ...-Fix-lapack-larfg-function-signature.patch |   7 +-
 integration_tests/recipes/scipy/test_scipy.py |   3 +-
 28 files changed, 274 insertions(+), 342 deletions(-)

diff --git a/integration_tests/recipes/libf2c/extras/make.inc b/integration_tests/recipes/libf2c/extras/make.inc
index 7eaae7b5..2995eaa1 100644
--- a/integration_tests/recipes/libf2c/extras/make.inc
+++ b/integration_tests/recipes/libf2c/extras/make.inc
@@ -1,80 +1,37 @@
 # -*- Makefile -*-
-####################################################################
-#  LAPACK make include file.                                       #
-#  LAPACK, Version 3.2.1                                           #
-#  June 2009		                                               #
-####################################################################
-#
-# See the INSTALL/ directory for more examples.
-#
-SHELL = /usr/bin/env sh
-#
-#  The machine (platform) identifier to append to the library names
-#
-# WA for WebAssembly
-PLAT = _WA
-#
-#  Modify the FORTRAN and OPTS definitions to refer to the
-#  compiler and desired compiler options for your machine.  NOOPT
-#  refers to the compiler options desired when NO OPTIMIZATION is
-#  selected.  Define LOADER and LOADOPTS to refer to the loader
-#  and desired load options for your machine.
-#
-#######################################################
-# This is used to compile C library
-#CC        = gcc  # inherit $CC from emmake
-# if no wrapping of the blas library is needed, uncomment next line
-#CC        = gcc -DNO_BLAS_WRAP
-CFLAGS    = -O3 -I$(TOPDIR)/INCLUDE -fPIC -DNO_BLAS_WRAP
-LDFLAGS	  = -O3
-LOADER    = $(CC)
-LOADOPTS  =
-NOOPT     = -O0 -I$(TOPDIR)/INCLUDE -fPIC
-DRVCFLAGS = $(CFLAGS)
-F2CCFLAGS = $(CFLAGS)
-#######################################################################
-
-#
-# Timer for the SECOND and DSECND routines
-#
-# Default : SECOND and DSECND will use a call to the EXTERNAL FUNCTION ETIME
-# TIMER    = EXT_ETIME
-# For RS6K : SECOND and DSECND will use a call to the EXTERNAL FUNCTION ETIME_
-# TIMER    = EXT_ETIME_
-# For gfortran compiler: SECOND and DSECND will use a call to the INTERNAL FUNCTION ETIME
-# TIMER    = INT_ETIME
-# If your Fortran compiler does not provide etime (like Nag Fortran Compiler, etc...)
-# SECOND and DSECND will use a call to the Fortran standard INTERNAL FUNCTION CPU_TIME
-TIMER    = INT_CPU_TIME
-# If neither of this works...you can use the NONE value... In that case, SECOND and DSECND will always return 0
-# TIMER     = NONE
-#
-#  The archiver and the flag(s) to use when building archive (library)
-#  If you system has no ranlib, set RANLIB = echo.
-#
-ARCH     = $(AR)
-ARCHFLAGS= cr
-#RANLIB   = ranlib
-#
-#  The location of BLAS library for linking the testing programs.
-#  The target's machine-specific, optimized BLAS library should be
-#  used whenever possible.
-#
-BLASLIB      = ../../blas$(PLAT).a
-#
-#  Location of the extended-precision BLAS (XBLAS) Fortran library
-#  used for building and testing extended-precision routines.  The
-#  relevant routines will be compiled and XBLAS will be linked only if
-#  USEXBLAS is defined.
-#
-# USEXBLAS    = Yes
-XBLASLIB     =
-# XBLASLIB    = -lxblas
-#
-#  Names of generated libraries.
-#
-LAPACKLIB    = lapack$(PLAT).a
-F2CLIB       = ../../F2CLIBS/libf2c.a
-TMGLIB       = tmglib$(PLAT).a
-EIGSRCLIB    = eigsrc$(PLAT).a
-LINSRCLIB    = linsrc$(PLAT).a
+#################################################################### # LAPACK
+make include file. # # LAPACK, Version 3.2.1 # # June 2009 #
+#################################################################### # # See the
+INSTALL/ directory for more examples. # SHELL = /usr/bin/env sh # # The machine
+(platform) identifier to append to the library names # # WA for WebAssembly PLAT
+= _WA # # Modify the FORTRAN and OPTS definitions to refer to the # compiler and
+desired compiler options for your machine. NOOPT # refers to the compiler
+options desired when NO OPTIMIZATION is # selected. Define LOADER and LOADOPTS
+to refer to the loader # and desired load options for your machine. #
+####################################################### # This is used to
+compile C library #CC = gcc # inherit $CC from emmake # if no wrapping of the
+blas library is needed, uncomment next line #CC = gcc -DNO_BLAS_WRAP CFLAGS =
+-O3 -I$(TOPDIR)/INCLUDE -fPIC -DNO_BLAS_WRAP LDFLAGS = -O3 LOADER = $(CC)
+LOADOPTS = NOOPT = -O0 -I$(TOPDIR)/INCLUDE -fPIC DRVCFLAGS = $(CFLAGS) F2CCFLAGS
+= $(CFLAGS)
+####################################################################### # #
+Timer for the SECOND and DSECND routines # # Default : SECOND and DSECND will
+use a call to the EXTERNAL FUNCTION ETIME # TIMER = EXT_ETIME # For RS6K :
+SECOND and DSECND will use a call to the EXTERNAL FUNCTION ETIME_ # TIMER =
+EXT_ETIME_ # For gfortran compiler: SECOND and DSECND will use a call to the
+INTERNAL FUNCTION ETIME # TIMER = INT_ETIME # If your Fortran compiler does not
+provide etime (like Nag Fortran Compiler, etc...) # SECOND and DSECND will use a
+call to the Fortran standard INTERNAL FUNCTION CPU_TIME TIMER = INT_CPU_TIME #
+If neither of this works...you can use the NONE value... In that case, SECOND
+and DSECND will always return 0 # TIMER = NONE # # The archiver and the flag(s)
+to use when building archive (library) # If you system has no ranlib, set RANLIB
+= echo. # ARCH = $(AR) ARCHFLAGS= cr #RANLIB = ranlib # # The location of BLAS
+library for linking the testing programs. # The target's machine-specific,
+optimized BLAS library should be # used whenever possible. # BLASLIB =
+../../blas$(PLAT).a # # Location of the extended-precision BLAS (XBLAS) Fortran
+library # used for building and testing extended-precision routines. The #
+relevant routines will be compiled and XBLAS will be linked only if # USEXBLAS
+is defined. # # USEXBLAS = Yes XBLASLIB = # XBLASLIB = -lxblas # # Names of
+generated libraries. # LAPACKLIB = lapack$(PLAT).a F2CLIB =
+../../F2CLIBS/libf2c.a TMGLIB = tmglib$(PLAT).a EIGSRCLIB = eigsrc$(PLAT).a
+LINSRCLIB = linsrc$(PLAT).a
diff --git a/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch b/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch
index 7773825a..04d995a1 100644
--- a/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch
+++ b/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch
@@ -22,9 +22,8 @@ index 0a3ed0d..a473ed8 100644
 -	rm -f a.out arithchk.o
 +	node a.out.js >arith.h
 +	rm -f a.out.js a.out.wasm
- 
+
  check:
  	xsum Notice README abort_.c arithchk.c backspac.c c_abs.c c_cos.c \
--- 
+--
 2.25.1
-
diff --git a/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch b/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch
index 89d94e5d..b7c68721 100644
--- a/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch
+++ b/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch
@@ -26,6 +26,5 @@ index a473ed8..e51d826 100644
  ## Under Solaris (and other systems that do not understand ld -x),
  ## omit -x in the ld line above.
  ## If your system does not have the ld command, comment out
--- 
+--
 2.25.1
-
diff --git a/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch b/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch
index bfd7257f..65a730a4 100644
--- a/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch
+++ b/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch
@@ -20,15 +20,14 @@ index 5f1eb22..32e669b 100644
 @@ -48,9 +48,9 @@ include ../make.inc
  #
  #######################################################################
- 
+
 -ALLAUX = maxloc.o ilaenv.o ieeeck.o lsamen.o xerbla.o xerbla_array.o iparmq.o	\
 +ALLAUX = maxloc.o ilaenv.o ieeeck.o lsamen.o iparmq.o	\
      ilaprec.o ilatrans.o ilauplo.o iladiag.o chla_transtype.o \
 -    ../INSTALL/ilaver.o ../INSTALL/lsame.o
 +    ../INSTALL/ilaver.o
- 
+
  ALLXAUX =
- 
--- 
-2.25.1
 
+--
+2.25.1
diff --git a/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch b/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch
index 5d95f705..6b05ba0e 100644
--- a/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch
+++ b/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch
@@ -48,9 +48,9 @@ index 8d92a63..54c4ff1 100644
 @@ -28,11 +28,11 @@ extern
  extern "C" {
  #endif
- 
+
 - VOID
-+ 
++
  #ifdef KR_headers
 -s_cat(lp, rpp, rnp, np, ll) char *lp, *rpp[]; ftnint rnp[], *np; ftnlen ll;
 +int s_cat(lp, rpp, rnp, np, ll) char *lp, *rpp[]; ftnint rnp[], *np; ftnlen ll;
@@ -66,7 +66,7 @@ index 9dacfc7..8d8963f 100644
 +++ b/F2CLIBS/libf2c/s_copy.c
 @@ -12,9 +12,9 @@ extern "C" {
  /* assign strings:  a = b */
- 
+
  #ifdef KR_headers
 -VOID s_copy(a, b, la, lb) register char *a, *b; ftnlen la, lb;
 +int s_copy(a, b, la, lb) register char *a, *b; ftnlen la, lb;
@@ -76,6 +76,5 @@ index 9dacfc7..8d8963f 100644
  #endif
  {
  	register char *aend, *bend;
--- 
+--
 2.25.1
-
diff --git a/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch b/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch
index 7dce211b..69c602ec 100644
--- a/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch
+++ b/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch
@@ -22,6 +22,5 @@ index 57eff0d..136050f 100644
  REAL =	r_abs.o r_acos.o r_asin.o r_atan.o r_atn2.o r_cnjg.o r_cos.o\
  	r_cosh.o r_dim.o r_exp.o r_imag.o r_int.o\
  	r_lg10.o r_log.o r_mod.o r_nint.o r_sign.o\
--- 
+--
 2.34.1
-
diff --git a/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch b/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch
index 336f3761..29b7c275 100644
--- a/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch
+++ b/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch
@@ -4,30 +4,30 @@ Index: CLAPACK-3.2.1/F2CLIBS/libf2c/Makefile
 +++ CLAPACK-3.2.1/F2CLIBS/libf2c/Makefile
 @@ -70,8 +70,8 @@ OFILES = $(MISC) $(POW) $(CX) $(DCX) $(R
  all: f2c.h signal1.h sysdep1.h libf2c.a clapack_install
- 
+
  libf2c.a: $(OFILES)
 -	ar r libf2c.a $?
 -	-ranlib libf2c.a
 +	$(ARCH) r libf2c.a $?
 +	$(RANLIB) libf2c.a
- 
+
  ## Shared-library variant: the following rule works on Linux
  ## systems.  Details are system-dependent.  Under Linux, -fPIC
 @@ -80,7 +80,7 @@ libf2c.a: $(OFILES)
  ## of "cc -shared".
- 
+
  libf2c.so: $(OFILES)
 -	cc -shared -o libf2c.so $(OFILES)
 +	$(CC) -shared -o libf2c.so $(OFILES)
- 
+
  ### If your system lacks ranlib, you don't need it; see README.
- 
+
 @@ -117,7 +117,7 @@ sysdep1.h: sysdep1.h0
- 
+
  install: libf2c.a
  	cp libf2c.a $(LIBDIR)
 -	-ranlib $(LIBDIR)/libf2c.a
 +	$(RANLIB) $(LIBDIR)/libf2c.a
- 
+
  clapack_install: libf2c.a
  	mv libf2c.a ..
diff --git a/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch b/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch
index ae57a81a..af738b5c 100644
--- a/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch
+++ b/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch
@@ -21,9 +21,8 @@ index 5f787a9c..6890046a 100644
  # Flags for POWER8 are defined in Makefile.power. Don't modify COMMON_OPT
 -# COMMON_OPT = -O2
 +COMMON_OPT = -O2 -Wno-return-type
- 
+
  # gfortran option for LAPACK to improve thread-safety
  # It is enabled by default in Makefile.system for gfortran
--- 
+--
 2.34.1
-
diff --git a/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch b/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
index d7ba240d..d65f0513 100644
--- a/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
+++ b/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
@@ -12,7 +12,7 @@ index fe7d6d898..74d3ca96a 100644
 --- a/lapack-netlib/SRC/xerbla_array.c
 +++ b/lapack-netlib/SRC/xerbla_array.c
 @@ -600,7 +600,7 @@ array.f"> */
- 
+
  /*  ===================================================================== */
  /* Subroutine */ void xerbla_array_(char *srname_array__, integer *
 -	srname_len__, integer *info, integer srname_array_len)
@@ -20,6 +20,5 @@ index fe7d6d898..74d3ca96a 100644
  {
      /* System generated locals */
      integer i__1, i__2, i__3;
--- 
+--
 2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch b/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
index ca6d80a0..ed81ec94 100644
--- a/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
+++ b/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
@@ -17,7 +17,7 @@ index 0d20ba1ca..d4325f71f 100644
                                double *work, CBLAS_INT *lwork, CBLAS_INT *iwork, CBLAS_INT *liwork,
 -                              CBLAS_INT *info, size_t jobz_len, size_t range_len);
 +                              CBLAS_INT *info);
- 
+
  static void c_dstevr(char *jobz, char *range, CBLAS_INT *n, double *d, double *e,
                       double *vl, double *vu, CBLAS_INT *il, CBLAS_INT *iu, double *abstol,
                       CBLAS_INT *m, double *w, double *z, CBLAS_INT *ldz, CBLAS_INT *isuppz,
@@ -27,6 +27,5 @@ index 0d20ba1ca..d4325f71f 100644
 -                      1, 1);
 +                      w, z, ldz, isuppz, work, lwork, iwork, liwork, info);
  }
--- 
+--
 2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0002-int-to-string.patch b/integration_tests/recipes/scipy/patches/0002-int-to-string.patch
index 7a172cb2..0467762e 100644
--- a/integration_tests/recipes/scipy/patches/0002-int-to-string.patch
+++ b/integration_tests/recipes/scipy/patches/0002-int-to-string.patch
@@ -24,6 +24,5 @@ index 7e180e4f8..b940bb702 100644
       1   i, lun, lunit, mesflg, ncpw, nch, nwds
        double precision r1, r2
        dimension msg(nmes)
--- 
+--
 2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch b/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch
index 3840f745..c975e17f 100644
--- a/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch
+++ b/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch
@@ -18,9 +18,9 @@ index dfc0516ac..92d7d7d6b 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h
 @@ -262,9 +262,9 @@ extern void    ccheck_tempv(int, singlecomplex *);
- 
+
  /*! \brief BLAS */
- 
+
 -extern int cgemm_(const char*, const char*, const int*, const int*, const int*,
 -                  const singlecomplex*, const singlecomplex*, const int*, const singlecomplex*,
 -		  const int*, const singlecomplex*, singlecomplex*, const int*);
@@ -35,9 +35,9 @@ index 3b5aa509f..1305641bd 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h
 @@ -260,9 +260,9 @@ extern void    dcheck_tempv(int, double *);
- 
+
  /*! \brief BLAS */
- 
+
 -extern int dgemm_(const char*, const char*, const int*, const int*, const int*,
 -                  const double*, const double*, const int*, const double*,
 -		  const int*, const double*, double*, const int*);
@@ -52,9 +52,9 @@ index 9bb6a38e7..b013962a4 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h
 @@ -259,9 +259,9 @@ extern void    scheck_tempv(int, float *);
- 
+
  /*! \brief BLAS */
- 
+
 -extern int sgemm_(const char*, const char*, const int*, const int*, const int*,
 -                  const float*, const float*, const int*, const float*,
 -		  const int*, const float*, float*, const int*);
@@ -69,9 +69,9 @@ index c6418d584..c5a2692be 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h
 @@ -262,9 +262,9 @@ extern void    zcheck_tempv(int, doublecomplex *);
- 
+
  /*! \brief BLAS */
- 
+
 -extern int zgemm_(const char*, const char*, const int*, const int*, const int*,
 -                  const doublecomplex*, const doublecomplex*, const int*, const doublecomplex*,
 -		  const int*, const doublecomplex*, doublecomplex*, const int*);
@@ -81,6 +81,5 @@ index c6418d584..c5a2692be 100644
  extern int ztrsv_(char*, char*, char*, int*, doublecomplex*, int*,
                    doublecomplex*, int*);
  extern int ztrsm_(char*, char*, char*, char*, int*, int*,
--- 
+--
 2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch b/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch
index 5abeb4f0..89894034 100644
--- a/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch
+++ b/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch
@@ -45,7 +45,7 @@ index f35c94f984..1872d335aa 100644
 @@ -71,7 +71,7 @@ double_complex F_FUNC(wzdotu,WZDOTU)(CBLAS_INT *n, double_complex *zx, \
      return ret;
  }
- 
+
 -void BLAS_FUNC(sladiv)(float *xr, float *xi, float *yr, float *yi, \
 +int BLAS_FUNC(sladiv)(float *xr, float *xi, float *yr, float *yi, \
      float *retr, float *reti);
@@ -54,7 +54,7 @@ index f35c94f984..1872d335aa 100644
 @@ -83,7 +83,7 @@ float_complex F_FUNC(wcladiv,WCLADIV)(float_complex *x, float_complex *y){
      return ret;
  }
- 
+
 -void BLAS_FUNC(dladiv)(double *xr, double *xi, double *yr, double *yi, \
 +int BLAS_FUNC(dladiv)(double *xr, double *xi, double *yr, double *yi, \
      double *retr, double *reti);
@@ -63,41 +63,41 @@ index f35c94f984..1872d335aa 100644
 @@ -95,31 +95,31 @@ double_complex F_FUNC(wzladiv,WZLADIV)(double_complex *x, double_complex *y){
      return ret;
  }
- 
+
 -void F_FUNC(cdotcwrp,WCDOTCWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
 +int F_FUNC(cdotcwrp,WCDOTCWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
          CBLAS_INT *incx, float_complex *cy, CBLAS_INT *incy){
      *ret = F_FUNC(wcdotc,WCDOTC)(n, cx, incx, cy, incy);
  }
- 
+
 -void F_FUNC(zdotcwrp,WZDOTCWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
 +int F_FUNC(zdotcwrp,WZDOTCWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
          CBLAS_INT *incx, double_complex *zy, CBLAS_INT *incy){
      *ret = F_FUNC(wzdotc,WZDOTC)(n, zx, incx, zy, incy);
  }
- 
+
 -void F_FUNC(cdotuwrp,CDOTUWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
 +int F_FUNC(cdotuwrp,CDOTUWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
          CBLAS_INT *incx, float_complex *cy, CBLAS_INT *incy){
      *ret = F_FUNC(wcdotu,WCDOTU)(n, cx, incx, cy, incy);
  }
- 
+
 -void F_FUNC(zdotuwrp,ZDOTUWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
 +int F_FUNC(zdotuwrp,ZDOTUWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
          CBLAS_INT *incx, double_complex *zy, CBLAS_INT *incy){
      *ret = F_FUNC(wzdotu,WZDOTU)(n, zx, incx, zy, incy);
  }
- 
+
 -void F_FUNC(cladivwrp,CLADIVWRP)(float_complex *ret, float_complex *x, float_complex *y){
 +int F_FUNC(cladivwrp,CLADIVWRP)(float_complex *ret, float_complex *x, float_complex *y){
      *ret = F_FUNC(wcladiv,WCLADIV)(x, y);
  }
- 
+
 -void F_FUNC(zladivwrp,ZLADIVWRP)(double_complex *ret, double_complex *x, double_complex *y){
 +int F_FUNC(zladivwrp,ZLADIVWRP)(double_complex *ret, double_complex *x, double_complex *y){
      *ret = F_FUNC(wzladiv,WZLADIV)(x, y);
  }
- 
+
 diff --git a/scipy/integrate/_odepackmodule.c b/scipy/integrate/_odepackmodule.c
 index 0c8067e652..d085939859 100644
 --- a/scipy/integrate/_odepackmodule.c
@@ -105,18 +105,18 @@ index 0c8067e652..d085939859 100644
 @@ -156,17 +156,17 @@ static PyObject *odepack_error;
      #endif
  #endif
- 
+
 -typedef void lsoda_f_t(F_INT *n, double *t, double *y, double *ydot);
 +typedef int lsoda_f_t(F_INT *n, double *t, double *y, double *ydot);
  typedef int lsoda_jac_t(F_INT *n, double *t, double *y, F_INT *ml, F_INT *mu,
                          double *pd, F_INT *nrowpd);
- 
+
 -void LSODA(lsoda_f_t *f, F_INT *neq, double *y, double *t, double *tout, F_INT *itol,
 +int LSODA(lsoda_f_t *f, F_INT *neq, double *y, double *t, double *tout, F_INT *itol,
             double *rtol, double *atol, F_INT *itask, F_INT *istate, F_INT *iopt,
             double *rwork, F_INT *lrw, F_INT *iwork, F_INT *liw, lsoda_jac_t *jac,
             F_INT *jt);
- 
+
  /*
 -void ode_function(int *n, double *t, double *y, double *ydot)
 +int ode_function(int *n, double *t, double *y, double *ydot)
@@ -126,7 +126,7 @@ index 0c8067e652..d085939859 100644
 @@ -175,7 +175,7 @@ void ode_function(int *n, double *t, double *y, double *ydot)
  }
  */
- 
+
 -void
 +int
  ode_function(F_INT *n, double *t, double *y, double *ydot)
@@ -138,8 +138,8 @@ index c806e33fbf..c4b822eb92 100644
 +++ b/scipy/odr/__odrpack.c
 @@ -13,7 +13,7 @@
  #include "odrpack.h"
- 
- 
+
+
 -void F_FUNC(dodrc,DODRC)(void (*fcn)(F_INT *n, F_INT *m, F_INT *np, F_INT *nq, F_INT *ldn, F_INT *ldm,
 +void F_FUNC(dodrc,DODRC)(int (*fcn)(F_INT *n, F_INT *m, F_INT *np, F_INT *nq, F_INT *ldn, F_INT *ldm,
              F_INT *ldnp, double *beta, double *xplusd, F_INT *ifixb, F_INT *ifixx,
@@ -152,7 +152,7 @@ index c1dc7fcf8f..d1903db4a6 100644
 @@ -23,10 +23,10 @@ at the top-level directory.
  #include 
  #include "slu_cdefs.h"
- 
+
 -extern void cswap_(int *, singlecomplex [], int *, singlecomplex [], int *);
 -extern void caxpy_(int *, singlecomplex *, singlecomplex [], int *, singlecomplex [], int *);
 -extern void ccopy_(int *, singlecomplex [], int *, singlecomplex [], int *);
@@ -171,10 +171,10 @@ index 4e2654e8ac..d5b955d40e 100644
 @@ -26,7 +26,7 @@ at the top-level directory.
  int num_drop_U;
  #endif
- 
+
 -extern void scopy_(int *, float [], int *, float [], int *);
 +extern int scopy_(int *, float [], int *, float [], int *);
- 
+
  #if 0
  static float *A;  /* used in _compare_ only */
 diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h
@@ -182,9 +182,9 @@ index 5afc93b5d9..7ac5f80fb9 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h
 @@ -3,6 +3,9 @@
- 
+
  #include 
- 
+
 +#include "f2c.h"
 +
 +
@@ -198,7 +198,7 @@ index 1395752d4c..7f5538140d 100644
 @@ -21,6 +21,8 @@ at the top-level directory.
   */
  #include "slu_sdefs.h"
- 
+
 +extern float slangs(char *, SuperMatrix *);
 +
  /*! \brief
@@ -207,10 +207,10 @@ index 1395752d4c..7f5538140d 100644
 @@ -377,8 +379,6 @@ sgssvx(superlu_options_t *options, SuperMatrix *A, int *perm_c, int *perm_r,
      double    t0;      /* temporary time */
      double    *utime;
- 
+
 -    /* External functions */
 -    extern float slangs(char *, SuperMatrix *);
- 
+
      Bstore = B->Store;
      Xstore = X->Store;
 @@ -573,7 +573,8 @@ printf("dgssvx: Fact=%4d, Trans=%4d, equed=%c\n",
@@ -230,21 +230,21 @@ index 67e83bcc77..e5757d5c4d 100644
 @@ -28,7 +28,10 @@ at the top-level directory.
  #ifndef DCOMPLEX_INCLUDE
  #define DCOMPLEX_INCLUDE
- 
+
 -typedef struct { double r, i; } doublecomplex;
 +#include"scipy_slu_config.h"
 +
 +// defined in clapack
 +//typedef struct { double r, i; } doublecomplex;
- 
- 
+
+
  /* Macro definitions */
 diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
 index 83be8c971f..047a07ce9c 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
 @@ -27,8 +27,9 @@ at the top-level directory.
- 
+
  #ifndef SCOMPLEX_INCLUDE
  #define SCOMPLEX_INCLUDE
 -
@@ -252,8 +252,8 @@ index 83be8c971f..047a07ce9c 100644
 +#include"scipy_slu_config.h"
 +// defined in  CLAPACK
 +//typedef struct { float r, i; } singlecomplex;
- 
- 
+
+
  /* Macro definitions */
 diff --git a/scipy/sparse/linalg/_dsolve/_superlu_utils.c b/scipy/sparse/linalg/_dsolve/_superlu_utils.c
 index 49b928a431..0822687719 100644
@@ -262,13 +262,13 @@ index 49b928a431..0822687719 100644
 @@ -243,12 +243,12 @@ int input_error(char *srname, int *info)
   * Stubs for Harwell Subroutine Library functions that SuperLU tries to call.
   */
- 
+
 -void mc64id_(int *a)
 +int mc64id_(int *a)
  {
      superlu_python_module_abort("chosen functionality not available");
  }
- 
+
 -void mc64ad_(int *a, int *b, int *c, int d[], int e[], double f[],
 +int mc64ad_(int *a, int *b, int *c, int d[], int e[], double f[],
  	     int *g, int h[], int *i, int j[], int *k, double l[],
@@ -281,8 +281,8 @@ index 5eb0bb1b3d..81a6efafb9 100644
 @@ -1,16 +1,16 @@
 -c
 +
- c\SCCS Information: @(#) 
- c FILE: debug.h   SID: 2.3   DATE OF SID: 11/16/95   RELEASE: 2 
+ c\SCCS Information: @(#)
+ c FILE: debug.h   SID: 2.3   DATE OF SID: 11/16/95   RELEASE: 2
  c
  c     %---------------------------------%
  c     | See debug.doc for documentation |
@@ -291,7 +291,7 @@ index 5eb0bb1b3d..81a6efafb9 100644
 -     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
 -     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
 -     &         mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd
--      common /debug/ 
+-      common /debug/
 -     &         logfil, ndigit, mgetv0,
 -     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
 -     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
@@ -310,8 +310,8 @@ index 66a8e9f87f..81d49c3bd2 100644
 --- a/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h
 +++ b/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h
 @@ -5,17 +5,17 @@ c
- c\SCCS Information: @(#) 
- c FILE: stat.h   SID: 2.2   DATE OF SID: 11/16/95   RELEASE: 2 
+ c\SCCS Information: @(#)
+ c FILE: stat.h   SID: 2.2   DATE OF SID: 11/16/95   RELEASE: 2
  c
 -      real       t0, t1, t2, t3, t4, t5
 -      save       t0, t1, t2, t3, t4, t5
@@ -323,7 +323,7 @@ index 66a8e9f87f..81d49c3bd2 100644
 -     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
 -     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
 -     &           tmvopx, tmvbx, tgetv0, titref, trvec
--      common /timing/ 
+-      common /timing/
 -     &           nopx, nbx, nrorth, nitref, nrstrt,
 -     &           tsaupd, tsaup2, tsaitr, tseigt, tsgets, tsapps, tsconv,
 -     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
@@ -340,6 +340,5 @@ index 66a8e9f87f..81d49c3bd2 100644
 +c     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
 +c     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
 +c     &           tmvopx, tmvbx, tgetv0, titref, trvec
--- 
+--
 2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch b/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch
index 1df3145c..ab621ea1 100644
--- a/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch
+++ b/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch
@@ -62,7 +62,7 @@ index f02569a40..1e4d65724 100644
 +      evapol = f
        return
        end
- 
+
 diff --git a/scipy/interpolate/fitpack/fprati.f b/scipy/interpolate/fitpack/fprati.f
 index 71c57eb01..97b5851df 100644
 --- a/scipy/interpolate/fitpack/fprati.f
@@ -107,6 +107,5 @@ index 02b00da6a..6024a0476 100644
    10  continue
        return
        end
--- 
+--
 2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch b/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch
index feabf913..058469f3 100644
--- a/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch
+++ b/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch
@@ -14,25 +14,24 @@ index 04037fdca..3686cea86 100644
 @@ -1196,8 +1196,8 @@ subroutine gees(compute_v,sort_t,select,n,a,nrows,sdim,w,vs,
      !  A = Z * T * Z^H  -- a complex matrix is in Schur form if it is upper
      !  triangular
- 
+
 -    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,w,vs,&ldvs,work,&lwork,rwork,bwork,&info,1,1)
 -    callprotoargument char*,char*,F_INT(*)(*),F_INT*,*,F_INT*,F_INT*,*,*,F_INT*,*,F_INT*,*,F_INT*,F_INT*,F_INT,F_INT
 +    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,w,vs,&ldvs,work,&lwork,rwork,bwork,&info)
 +    callprotoargument char*,char*,F_INT(*)(*),F_INT*,*,F_INT*,F_INT*,*,*,F_INT*,*,F_INT*,*,F_INT*,F_INT*
- 
+
      use gees__user__routines
- 
+
 @@ -1226,8 +1226,8 @@ subroutine gees(compute_v,sort_t,select,n,a,nrows,sdim,wr,wi,v
      !  A = Z * T * Z^H  -- a real matrix is in Schur form if it is upper quasi-
      !  triangular with 1x1 and 2x2 blocks.
- 
+
 -    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,wr,wi,vs,&ldvs,work,&lwork,bwork,&info,1,1)
 -    callprotoargument char*,char*,F_INT(*)(*,*),F_INT*,*,F_INT*,F_INT*,*,*,*,F_INT*,*,F_INT*,F_INT*,F_INT*,F_INT,F_INT
 +    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,wr,wi,vs,&ldvs,work,&lwork,bwork,&info)
 +    callprotoargument char*,char*,F_INT(*)(*,*),F_INT*,*,F_INT*,F_INT*,*,*,*,F_INT*,*,F_INT*,F_INT*,F_INT*
- 
+
      use gees__user__routines
- 
--- 
-2.34.1
 
+--
+2.34.1
diff --git a/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch b/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
index e3a57c5b..b13156ca 100644
--- a/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
+++ b/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
@@ -134,11 +134,11 @@ index 4417af39dc..4bdbdf9750 100644
 @@ -140,7 +140,7 @@ ignore_missing_imports = True
  [mypy-scipy.linalg._solve_toeplitz]
  ignore_missing_imports = True
- 
+
 -[mypy-scipy.linalg._interpolative]
 +[mypy-scipy.linalg._decomp_interpolative]
  ignore_missing_imports = True
- 
+
  [mypy-scipy.optimize._group_columns]
 diff --git a/scipy/linalg/_decomp_interpolative.pyx b/scipy/linalg/_decomp_interpolative.pyx
 new file mode 100644
@@ -3843,36 +3843,36 @@ index b91cdd63a..f946b059f 100644
 -
 -# Python module for interfacing with `id_dist`.
 +#  ******************************************************************************
- 
+
  r"""
  ======================================================================
  Interpolative matrix decomposition (:mod:`scipy.linalg.interpolative`)
  ======================================================================
- 
+
 -.. moduleauthor:: Kenneth L. Ho 
 -
  .. versionadded:: 0.13
- 
+
 +.. versionchanged:: 1.15.0
 +    The underlying algorithms have been ported to Python from the original Fortran77
 +    code. See references below for more details.
 +
  .. currentmodule:: scipy.linalg.interpolative
- 
+
  An interpolative decomposition (ID) of a matrix :math:`A \in
 @@ -94,7 +94,7 @@ Main functionality:
     estimate_spectral_norm_diff
     estimate_rank
- 
+
 -Support functions:
 +Following support functions are deprecated and will be removed in SciPy 1.17.0:
- 
+
  .. autosummary::
     :toctree: generated/
 @@ -106,16 +106,13 @@ Support functions:
  References
  ==========
- 
+
 -This module uses the ID software package [1]_ by Martinsson, Rokhlin,
 -Shkolnisky, and Tygert, which is a Fortran library for computing IDs
 -using various algorithms, including the rank-revealing QR approach of
@@ -3884,17 +3884,17 @@ index b91cdd63a..f946b059f 100644
 +Rokhlin, Shkolnisky, and Tygert, which is a Fortran library for computing IDs using
 +various algorithms, including the rank-revealing QR approach of [2]_ and the more
 +recent randomized methods described in [3]_, [4]_, and [5]_.
- 
+
 -We advise the user to consult also the `documentation for the ID package
 -`_.
 +We advise the user to consult also the documentation for the `ID package
 +`_.
- 
+
  .. [1] P.G. Martinsson, V. Rokhlin, Y. Shkolnisky, M. Tygert. "ID: a
      software package for low-rank approximation of matrices via interpolative
 @@ -356,25 +353,8 @@ depending on the representation. The parameter ``eps`` controls the definition
  of the numerical rank.
- 
+
  Finally, the random number generation required for all randomized routines can
 -be controlled via :func:`scipy.linalg.interpolative.seed`. To reset the seed
 -values to their original values, use:
@@ -3917,23 +3917,23 @@ index b91cdd63a..f946b059f 100644
 -where ``n`` is the number of random numbers to generate.
 +be controlled via providing NumPy pseudo-random generators with a fixed seed. See
 +:class:`numpy.random.Generator` and :func:`numpy.random.default_rng` for more details.
- 
+
  Remarks
  -------
 @@ -385,9 +365,9 @@ backend routine.
- 
+
  """
- 
+
 -import scipy.linalg._interpolative_backend as _backend
 +import scipy.linalg._decomp_interpolative as _backend
  import numpy as np
 -import sys
 +import warnings
- 
+
  __all__ = [
      'estimate_rank',
 @@ -405,9 +385,18 @@ __all__ = [
- 
+
  _DTYPE_ERROR = ValueError("invalid input dtype (input must be float64 or complex128)")
  _TYPE_ERROR = TypeError("invalid input type (must be array or LinearOperator)")
 -_32BIT_ERROR = ValueError("interpolative decomposition on 32-bit systems "
@@ -3951,11 +3951,11 @@ index b91cdd63a..f946b059f 100644
 +    else:
 +        A = np.ascontiguousarray(A)
 +    return A
- 
- 
+
+
  def _is_real(A):
 @@ -424,53 +413,29 @@ def _is_real(A):
- 
+
  def seed(seed=None):
      """
 -    Seed the internal random number generator used in this ID package.
@@ -3979,7 +3979,7 @@ index b91cdd63a..f946b059f 100644
 -        initialize the generator.
 +    This function, historically, used to set the seed of the randomization algorithms
 +    used in the `scipy.linalg.interpolative` functions written in Fortran77.
- 
+
 +    The library has been ported to Python and now the functions use the native NumPy
 +    generators and this function has no content and returns None. Thus this function
 +    should not be used and will be removed in SciPy version 1.17.0.
@@ -4003,8 +4003,8 @@ index b91cdd63a..f946b059f 100644
 -        _backend.id_srandi(rnd.rand(55))
 +    warnings.warn("`scipy.linalg.interpolative.seed` is deprecated and will be "
 +                  "removed in SciPy 1.17.0.", DeprecationWarning, stacklevel=3)
- 
- 
+
+
  def rand(*shape):
      """
 -    Generate standard uniform pseudorandom numbers via a very efficient lagged
@@ -4012,7 +4012,7 @@ index b91cdd63a..f946b059f 100644
 +    This function, historically, used to generate uniformly distributed random number
 +    for the randomization algorithms used in the `scipy.linalg.interpolative` functions
 +    written in Fortran77.
- 
+
 -    This routine is used for all random number generation in this package and
 -    can affect ID and SVD results.
 +    The library has been ported to Python and now the functions use the native NumPy
@@ -4021,12 +4021,12 @@ index b91cdd63a..f946b059f 100644
 +
 +    If pseudo-random numbers are needed, NumPy pseudo-random generators should be used
 +    instead.
- 
+
      Parameters
      ----------
 @@ -478,11 +443,13 @@ def rand(*shape):
          Shape of output array
- 
+
      """
 -    # For details, see :func:`_backend.id_srand`, and :func:`_backend.id_srando`.
 -    return _backend.id_srand(np.prod(shape)).reshape(shape)
@@ -4034,13 +4034,13 @@ index b91cdd63a..f946b059f 100644
 +                  "removed in SciPy 1.17.0.", DeprecationWarning, stacklevel=3)
 +    rng = np.random.default_rng()
 +    return rng.uniform(low=0., high=1.0, size=shape)
- 
- 
+
+
 -def interp_decomp(A, eps_or_k, rand=True):
 +def interp_decomp(A, eps_or_k, rand=True, rng=None):
      """
      Compute ID of a matrix.
- 
+
 @@ -546,6 +513,9 @@ def interp_decomp(A, eps_or_k, rand=True):
          Whether to use random sampling if `A` is of type :class:`numpy.ndarray`
          (randomized algorithms are always used if `A` is of type
@@ -4048,12 +4048,12 @@ index b91cdd63a..f946b059f 100644
 +    rng : :class:`numpy.random.Generator`
 +        NumPy generator for the randomization steps in the algorithm. If ``rand`` is
 +        ``False``, the argument is ignored.
- 
+
      Returns
      -------
 @@ -562,57 +532,49 @@ def interp_decomp(A, eps_or_k, rand=True):
      real = _is_real(A)
- 
+
      if isinstance(A, np.ndarray):
 +        A = _C_contiguous_copy(A)
          if eps_or_k < 1:
@@ -4124,7 +4124,7 @@ index b91cdd63a..f946b059f 100644
 +            return idx, proj
      else:
          raise _TYPE_ERROR
- 
+
 @@ -648,9 +610,9 @@ def reconstruct_matrix_from_id(B, idx, proj):
          Reconstructed matrix.
      """
@@ -4134,20 +4134,20 @@ index b91cdd63a..f946b059f 100644
      else:
 -        return _backend.idz_reconid(B, idx + 1, proj)
 +        return _backend.idz_reconid(B, idx, proj)
- 
- 
+
+
  def reconstruct_interp_matrix(idx, proj):
 @@ -662,10 +624,8 @@ def reconstruct_interp_matrix(idx, proj):
- 
+
          P = numpy.hstack([numpy.eye(proj.shape[0]), proj])[:,numpy.argsort(idx)]
- 
+
 -    The original matrix can then be reconstructed from its skeleton matrix `B`
 -    via::
 -
 -        numpy.dot(B, P)
 +    The original matrix can then be reconstructed from its skeleton matrix ``B``
 +    via ``A = B @ P``
- 
+
      See also :func:`reconstruct_matrix_from_id` and
      :func:`reconstruct_skel_matrix`.
 @@ -677,7 +637,7 @@ def reconstruct_interp_matrix(idx, proj):
@@ -4158,7 +4158,7 @@ index b91cdd63a..f946b059f 100644
 +        1D column index array.
      proj : :class:`numpy.ndarray`
          Interpolation coefficients.
- 
+
 @@ -686,10 +646,17 @@ def reconstruct_interp_matrix(idx, proj):
      :class:`numpy.ndarray`
          Interpolation matrix.
@@ -4176,8 +4176,8 @@ index b91cdd63a..f946b059f 100644
 +    p[:, idx[krank:]] = proj[:, :]
 +
 +    return p
- 
- 
+
+
  def reconstruct_skel_matrix(A, k, idx):
 @@ -726,10 +693,7 @@ def reconstruct_skel_matrix(A, k, idx):
      :class:`numpy.ndarray`
@@ -4188,8 +4188,8 @@ index b91cdd63a..f946b059f 100644
 -    else:
 -        return _backend.idz_copycols(A, k, idx + 1)
 +    return A[:, idx[:k]]
- 
- 
+
+
  def id_to_svd(B, idx, proj):
 @@ -753,7 +717,7 @@ def id_to_svd(B, idx, proj):
      B : :class:`numpy.ndarray`
@@ -4199,7 +4199,7 @@ index b91cdd63a..f946b059f 100644
 +        1D column index array.
      proj : :class:`numpy.ndarray`
          Interpolation coefficients.
- 
+
 @@ -766,14 +730,16 @@ def id_to_svd(B, idx, proj):
      V : :class:`numpy.ndarray`
          Right singular vectors.
@@ -4213,20 +4213,20 @@ index b91cdd63a..f946b059f 100644
 +        U, S, V = _backend.idz_id2svd(B, idx, proj)
 +
      return U, S, V
- 
- 
+
+
 -def estimate_spectral_norm(A, its=20):
 +def estimate_spectral_norm(A, its=20, rng=None):
      """
      Estimate spectral norm of a matrix by the randomized power method.
- 
+
 @@ -788,6 +754,8 @@ def estimate_spectral_norm(A, its=20):
          `matvec` and `rmatvec` methods (to apply the matrix and its adjoint).
      its : int, optional
          Number of power method iterations.
 +    rng : :class:`numpy.random.Generator`
 +        NumPy generator for the randomization steps in the algorithm.
- 
+
      Returns
      -------
 @@ -796,18 +764,14 @@ def estimate_spectral_norm(A, its=20):
@@ -4245,8 +4245,8 @@ index b91cdd63a..f946b059f 100644
      else:
 -        return _backend.idz_snorm(m, n, matveca, matvec, its=its)
 +        return _backend.idz_snorm(A, its=its, rng=rng)
- 
- 
+
+
 -def estimate_spectral_norm_diff(A, B, its=20):
 +def estimate_spectral_norm_diff(A, B, its=20, rng=None):
      """
@@ -4258,7 +4258,7 @@ index b91cdd63a..f946b059f 100644
          Number of power method iterations.
 +    rng : :class:`numpy.random.Generator`
 +        NumPy generator for the randomization steps in the algorithm.
- 
+
      Returns
      -------
 @@ -835,30 +801,20 @@ def estimate_spectral_norm_diff(A, B, its=20):
@@ -4283,20 +4283,20 @@ index b91cdd63a..f946b059f 100644
 -        return _backend.idz_diffsnorm(
 -            m, n, matveca1, matveca2, matvec1, matvec2, its=its)
 +        return _backend.idz_diffsnorm(A, B, its=its, rng=rng)
- 
- 
+
+
 -def svd(A, eps_or_k, rand=True):
 +def svd(A, eps_or_k, rand=True, rng=None):
      """
      Compute SVD of a matrix via an ID.
- 
+
      An SVD of a matrix `A` is a factorization::
- 
+
 -        A = numpy.dot(U, numpy.dot(numpy.diag(S), V.conj().T))
 +        A = U @ np.diag(S) @ V.conj().T
- 
+
      where `U` and `V` have orthonormal columns and `S` is nonnegative.
- 
+
 @@ -889,35 +845,39 @@ def svd(A, eps_or_k, rand=True):
          Whether to use random sampling if `A` is of type :class:`numpy.ndarray`
          (randomized algorithms are always used if `A` is of type
@@ -4304,7 +4304,7 @@ index b91cdd63a..f946b059f 100644
 +    rng : :class:`numpy.random.Generator`
 +        NumPy generator for the randomization steps in the algorithm. If ``rand`` is
 +        ``False``, the argument is ignored.
- 
+
      Returns
      -------
      U : :class:`numpy.ndarray`
@@ -4318,9 +4318,9 @@ index b91cdd63a..f946b059f 100644
 +        2D array right singular vectors.
      """
      from scipy.sparse.linalg import LinearOperator
- 
+
      real = _is_real(A)
- 
+
      if isinstance(A, np.ndarray):
 +        A = _C_contiguous_copy(A)
          if eps_or_k < 1:
@@ -4395,8 +4395,8 @@ index b91cdd63a..f946b059f 100644
      else:
          raise _TYPE_ERROR
      return U, S, V
- 
- 
+
+
 -def estimate_rank(A, eps):
 +def estimate_rank(A, eps, rng=None):
      """
@@ -4408,12 +4408,12 @@ index b91cdd63a..f946b059f 100644
          Relative error for numerical rank definition.
 +    rng : :class:`numpy.random.Generator`
 +        NumPy generator for the randomization steps in the algorithm.
- 
+
      Returns
      -------
 @@ -996,20 +949,19 @@ def estimate_rank(A, eps):
      real = _is_real(A)
- 
+
      if isinstance(A, np.ndarray):
 +        A = _C_contiguous_copy(A)
          if real:
@@ -4442,9 +4442,9 @@ index cc208092e..777edd008 100644
 --- a/scipy/linalg/meson.build
 +++ b/scipy/linalg/meson.build
 @@ -111,57 +111,15 @@ py3.extension_module('_flapack',
- 
+
  # TODO: cblas/clapack are built *only* for ATLAS. Why? Is it still needed?
- 
+
 -# id_dist contains a copy of FFTPACK, which has type mismatch warnings
 -# that are hard to fix. This code is terrible and noisy during the build,
 -# silence it completely.
@@ -4504,7 +4504,7 @@ index cc208092e..777edd008 100644
 -  link_language: 'fortran',
    subdir: 'scipy/linalg'
  )
- 
+
 @@ -278,7 +236,6 @@ python_sources = [
    '_decomp_schur.py',
    '_decomp_svd.py',
@@ -5080,7 +5080,7 @@ index 8bcece8c4..000000000
 -%
 -{\tt idd\_qrmatvec} & applies to a single vector the $Q$ matrix (or its
 -transpose) in the $QR$ decomposition of a matrix, as described by the
--output of routines {\tt iddp\_qrpiv} or {\tt iddr\_qrpiv}; to apply $Q$ 
+-output of routines {\tt iddp\_qrpiv} or {\tt iddr\_qrpiv}; to apply $Q$
 -(or its transpose) to several vectors efficiently, use routine
 -{\tt idd\_qrmatmat} instead & {\tt idd\_qrpiv.f} \\\hline
 -%
@@ -5251,7 +5251,7 @@ index 8bcece8c4..000000000
 -%
 -{\tt idz\_qrmatvec} & applies to a single vector the $Q$ matrix (or its
 -adjoint) in the $QR$ decomposition of a matrix, as described by the
--output of routines {\tt idzp\_qrpiv} or {\tt idzr\_qrpiv}; to apply $Q$ 
+-output of routines {\tt idzp\_qrpiv} or {\tt idzr\_qrpiv}; to apply $Q$
 -(or its adjoint) to several vectors efficiently, use routine
 -{\tt idz\_qrmatmat} instead & {\tt idz\_qrpiv.f} \\\hline
 -%
@@ -5373,7 +5373,7 @@ index 8bcece8c4..000000000
 -in the comments immediately following the declaration
 -of the subroutine's calling sequence.
 -This documentation describes the purpose of the routine,
--the input and output variables, and the required work arrays (if any). 
+-the input and output variables, and the required work arrays (if any).
 -This documentation also cites relevant references.
 -Please pay attention to the {\it N.B.}'s;
 -{\it N.B.} stands for {\it nota bene} (Latin for ``note well'')
@@ -5547,10 +5547,10 @@ index ac2638c23..000000000
 -%%
 -%% supertabular.dtx  (with options: `package')
 -%% Copyright (C) 1989-2004 Johannes Braams. All rights reserved.
--%% 
+-%%
 -%% This file was generated from file(s) of the supertabular package.
 -%% -----------------------------------------------------------------
--%% 
+-%%
 -%% It may be distributed and/or modified under the
 -%% conditions of the LaTeX Project Public License, either version 1.3
 -%% of this license or (at your option) any later version.
@@ -5558,18 +5558,18 @@ index ac2638c23..000000000
 -%%   http://www.latex-project.org/lppl.txt
 -%% and version 1.3 or later is part of all distributions of LaTeX
 -%% version 2003/12/01 or later.
--%% 
+-%%
 -%% This work has the LPPL maintenance status "maintained".
--%% 
+-%%
 -%% The Current Maintainer of this work is Johannes Braams.
--%% 
+-%%
 -%% This file may only be distributed together with a copy of the
 -%% supertabular package. You may however distribute the supertabular package
 -%% without such generated files.
--%% 
+-%%
 -%% The list of all files belonging to the supertabular package is
 -%% given in the file `manifest.txt.
--%% 
+-%%
 -%% The list of derived (unpacked) files belonging to the distribution
 -%% and covered by LPPL is defined by the unpacking scripts (with
 -%% extension .ins) which are part of the distribution.
@@ -15334,7 +15334,7 @@ index 2dc811148..000000000
 -        subroutine iddr_aid(m,n,a,krank,w,list,proj)
 -c
 -c       computes the ID of the matrix a, i.e., lists in list
--c       the indices of krank columns of a such that 
+-c       the indices of krank columns of a such that
 -c
 -c       a(j,list(k))  =  a(j,list(k))
 -c
@@ -21574,7 +21574,7 @@ index 679590d84..000000000
 -        IQ=IQ1
 -
 -        RETURN
--  
+-
 -C
 -C
 -C
@@ -21687,7 +21687,7 @@ index ddc56f7c7..95b83dfad 100644
  #   POSSIBILITY OF SUCH DAMAGE.
 -#******************************************************************************
 +#  ******************************************************************************
- 
+
  import scipy.linalg.interpolative as pymatrixid
  import numpy as np
 @@ -36,8 +36,6 @@ from numpy.testing import (assert_, assert_allclose, assert_equal,
@@ -21696,13 +21696,13 @@ index ddc56f7c7..95b83dfad 100644
  from pytest import raises as assert_raises
 -import sys
 -_IS_32BIT = (sys.maxsize < 2**32)
- 
- 
+
+
  @pytest.fixture()
 @@ -45,6 +43,12 @@ def eps():
      yield 1e-12
- 
- 
+
+
 +@pytest.fixture()
 +def rng():
 +    rng = np.random.default_rng(1718313768084012)
@@ -21722,12 +21722,12 @@ index ddc56f7c7..95b83dfad 100644
 +    def test_real_id_fixed_precision(self, A, L, eps, rand, lin_op, rng):
          # Test ID routines on a Hilbert matrix.
          A_or_L = A if not lin_op else L
- 
+
 -        k, idx, proj = pymatrixid.interp_decomp(A_or_L, eps, rand=rand)
 +        k, idx, proj = pymatrixid.interp_decomp(A_or_L, eps, rand=rand, rng=rng)
          B = pymatrixid.reconstruct_matrix_from_id(A[:, idx[:k]], idx, proj)
          assert_allclose(A, B, rtol=eps, atol=1e-08)
- 
+
      @pytest.mark.parametrize(
          "rand,lin_op",
          [(False, False), (True, False), (True, True)])
@@ -21737,19 +21737,19 @@ index ddc56f7c7..95b83dfad 100644
 +    def test_real_id_fixed_rank(self, A, L, eps, rank, rand, lin_op, rng):
          k = rank
          A_or_L = A if not lin_op else L
- 
+
 -        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand)
 +        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand, rng=rng)
          B = pymatrixid.reconstruct_matrix_from_id(A[:, idx[:k]], idx, proj)
          assert_allclose(A, B, rtol=eps, atol=1e-08)
- 
+
      @pytest.mark.parametrize("rand,lin_op", [(False, False)])
      def test_real_id_skel_and_interp_matrices(
 -            self, A, L, eps, rank, rand, lin_op):
 +            self, A, L, eps, rank, rand, lin_op, rng):
          k = rank
          A_or_L = A if not lin_op else L
- 
+
 -        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand)
 +        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand, rng=rng)
          P = pymatrixid.reconstruct_interp_matrix(idx, proj)
@@ -21764,12 +21764,12 @@ index ddc56f7c7..95b83dfad 100644
 -            pytest.xfail("bug in external fortran code")
 +    def test_svd_fixed_precision(self, A, L, eps, rand, lin_op, rng):
          A_or_L = A if not lin_op else L
- 
+
 -        U, S, V = pymatrixid.svd(A_or_L, eps, rand=rand)
 +        U, S, V = pymatrixid.svd(A_or_L, eps, rand=rand, rng=rng)
          B = U * S @ V.T.conj()
          assert_allclose(A, B, rtol=eps, atol=1e-08)
- 
+
      @pytest.mark.parametrize(
          "rand,lin_op",
          [(False, False), (True, False), (True, True)])
@@ -21779,23 +21779,23 @@ index ddc56f7c7..95b83dfad 100644
 +    def test_svd_fixed_rank(self, A, L, eps, rank, rand, lin_op, rng):
          k = rank
          A_or_L = A if not lin_op else L
- 
+
 -        U, S, V = pymatrixid.svd(A_or_L, k, rand=rand)
 +        U, S, V = pymatrixid.svd(A_or_L, k, rand=rand, rng=rng)
          B = U * S @ V.T.conj()
          assert_allclose(A, B, rtol=eps, atol=1e-08)
- 
+
 @@ -141,59 +137,39 @@ class TestInterpolativeDecomposition:
          B = U * S @ V.T.conj()
          assert_allclose(A, B, rtol=eps, atol=1e-08)
- 
+
 -    def test_estimate_spectral_norm(self, A):
 +    def test_estimate_spectral_norm(self, A, rng):
          s = svdvals(A)
 -        norm_2_est = pymatrixid.estimate_spectral_norm(A)
 +        norm_2_est = pymatrixid.estimate_spectral_norm(A, rng=rng)
          assert_allclose(norm_2_est, s[0], rtol=1e-6, atol=1e-8)
- 
+
 -    def test_estimate_spectral_norm_diff(self, A):
 +    def test_estimate_spectral_norm_diff(self, A, rng):
          B = A.copy()
@@ -21804,11 +21804,11 @@ index ddc56f7c7..95b83dfad 100644
 -        norm_2_est = pymatrixid.estimate_spectral_norm_diff(A, B)
 +        norm_2_est = pymatrixid.estimate_spectral_norm_diff(A, B, rng=rng)
          assert_allclose(norm_2_est, s[0], rtol=1e-6, atol=1e-8)
- 
+
 -    def test_rank_estimates_array(self, A):
 +    def test_rank_estimates_array(self, A, rng):
          B = np.array([[1, 1, 0], [0, 0, 1], [0, 0, 1]], dtype=A.dtype)
- 
+
          for M in [A, B]:
              rank_tol = 1e-9
              rank_np = np.linalg.matrix_rank(M, norm(M, 2) * rank_tol)
@@ -21816,11 +21816,11 @@ index ddc56f7c7..95b83dfad 100644
 +            rank_est = pymatrixid.estimate_rank(M, rank_tol, rng=rng)
              assert_(rank_est >= rank_np)
              assert_(rank_est <= rank_np + 10)
- 
+
 -    def test_rank_estimates_lin_op(self, A):
 +    def test_rank_estimates_lin_op(self, A, rng):
          B = np.array([[1, 1, 0], [0, 0, 1], [0, 0, 1]], dtype=A.dtype)
- 
+
          for M in [A, B]:
              ML = aslinearoperator(M)
              rank_tol = 1e-9
@@ -21829,7 +21829,7 @@ index ddc56f7c7..95b83dfad 100644
 +            rank_est = pymatrixid.estimate_rank(ML, rank_tol, rng=rng)
              assert_(rank_est >= rank_np - 4)
              assert_(rank_est <= rank_np + 4)
- 
+
 -    def test_rand(self):
 -        pymatrixid.seed('default')
 -        assert_allclose(pymatrixid.rand(2), [0.8932059, 0.64500803],
@@ -21862,6 +21862,5 @@ index ddc56f7c7..95b83dfad 100644
          A = np.array([[-1, -1, -1, 0, 0, 0],
                        [0, 0, 0, 1, 1, 1],
                        [1, 0, 0, 1, 0, 0],
--- 
+--
 2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch b/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
index 705d648d..e84bf4d1 100644
--- a/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
+++ b/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
@@ -15,24 +15,23 @@ index 41afa7e74..5065a15ff 100644
  *          Pullman, WA 99164-3113
  *          Email : alangenz@wsu.edu
  *
--      SUBROUTINE mvnun(d, n, lower, upper, means, covar, maxpts, 
+-      SUBROUTINE mvnun(d, n, lower, upper, means, covar, maxpts,
 -     &                   abseps, releps, value, inform)
-+      RECURSIVE SUBROUTINE mvnun(d, n, lower, upper, means, covar, 
++      RECURSIVE SUBROUTINE mvnun(d, n, lower, upper, means, covar,
 +     &                   maxpts, abseps, releps, value, inform)
  *  Parameters
  *
  *   d       integer, dimensionality of the data
 @@ -88,8 +88,8 @@
-       END 
- 
- 
+       END
+
+
 -      SUBROUTINE mvnun_weighted(d, n, lower, upper, means, weights,
--     &                          covar, maxpts, abseps, releps, 
-+      recursive SUBROUTINE mvnun_weighted(d, n, lower, upper, means, 
+-     &                          covar, maxpts, abseps, releps,
++      recursive SUBROUTINE mvnun_weighted(d, n, lower, upper, means,
 +     &                          weights, covar, maxpts, abseps, releps,
       &                           value, inform)
  *  Parameters
  *
--- 
+--
 2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch b/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
index 0ca5929f..59f8c897 100644
--- a/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
+++ b/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
@@ -17,7 +17,7 @@ index ca74f7a..c447a6a 100644
 @@ -2,8 +2,8 @@ c
  c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
  c
- 
+
 -      subroutine zreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
 -     c     iflag)
 +      recursive subroutine zreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
@@ -28,10 +28,10 @@ index ca74f7a..c447a6a 100644
 @@ -103,7 +103,7 @@ c
  c****************************************************************************
  c
- 
+
 -      subroutine zcgs(n,k,V,ldv,vnew,index,work)
 +      recursive subroutine zcgs(n,k,V,ldv,vnew,index,work)
- 
+
  c     Block  Gram-Schmidt orthogonalization:
  c     FOR i= 1:l
 diff --git a/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F b/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F
@@ -41,7 +41,7 @@ index cd87247..e657a89 100644
 @@ -2,8 +2,8 @@ c
  c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
  c
- 
+
 -      subroutine creorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
 -     c     iflag)
 +      recursive subroutine creorth(n,k,V,ldv,vnew,normvnew,index,alpha,
@@ -52,10 +52,10 @@ index cd87247..e657a89 100644
 @@ -103,7 +103,7 @@ c
  c****************************************************************************
  c
- 
+
 -      subroutine ccgs(n,k,V,ldv,vnew,index,work)
 +      recursive subroutine ccgs(n,k,V,ldv,vnew,index,work)
- 
+
  c     Block  Gram-Schmidt orthogonalization:
  c     FOR i= 1:l
 diff --git a/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F b/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F
@@ -65,7 +65,7 @@ index 841208a..fec923e 100644
 @@ -2,8 +2,8 @@ c
  c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
  c
- 
+
 -      subroutine dreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
 -     c     iflag)
 +      recursive subroutine dreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
@@ -76,10 +76,10 @@ index 841208a..fec923e 100644
 @@ -103,7 +103,7 @@ c
  c****************************************************************************
  c
- 
+
 -      subroutine dcgs(n,k,V,ldv,vnew,index,work)
 +      recursive subroutine dcgs(n,k,V,ldv,vnew,index,work)
- 
+
  c     Block  Gram-Schmidt orthogonalization:
  c     FOR i= 1:l
 diff --git a/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F b/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F
@@ -89,7 +89,7 @@ index 644d404..61b6698 100644
 @@ -2,8 +2,8 @@ c
  c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
  c
- 
+
 -      subroutine sreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
 -     c     iflag)
 +      recursive subroutine sreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
@@ -100,12 +100,11 @@ index 644d404..61b6698 100644
 @@ -103,7 +103,7 @@ c
  c****************************************************************************
  c
- 
+
 -      subroutine scgs(n,k,V,ldv,vnew,index,work)
 +      recursive subroutine scgs(n,k,V,ldv,vnew,index,work)
- 
+
  c     Block  Gram-Schmidt orthogonalization:
  c     FOR i= 1:l
--- 
+--
 2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch b/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
index ad975ccd..f30a8499 100644
--- a/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
+++ b/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
@@ -72,5 +72,5 @@ index bb43e3b2e9..358279a93b 100644
    link_args: version_link_args,
    install: true,
    link_language: 'fortran',
--- 
+--
 2.39.3 (Apple Git-146)
diff --git a/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch b/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
index 78272f58..f9e1538d 100644
--- a/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
+++ b/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
@@ -89,6 +89,5 @@ index 75a58c40ec..215f38f31f 100644
    60  continue
    70  ier = 0
    80  return
--- 
+--
 2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch b/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch
index c4afc190..1edf5e07 100644
--- a/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch
+++ b/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch
@@ -22,6 +22,5 @@ index 1f3dc226ab..28aa8b8c22 100644
  void chpcon(char *uplo, int *n, c *ap, int *ipiv, s *anorm, s *rcond, c *work, int *info)
  void chpev(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, s *rwork, int *info)
  void chpevd(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, int *lwork, s *rwork, int *lrwork, int *iwork, int *liwork, int *info)
--- 
+--
 2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch b/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch
index c20be03f..7c9e357f 100644
--- a/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch
+++ b/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch
@@ -20,6 +20,5 @@ index 8a00f5d279..aeb86e8926 100644
      blas_macro, blas_name = get_blas_macro_and_name(name, accelerate)
      c_args = ', '.join(f'{t} *{n}' for t, n in zip(c_argtypes, argnames))
      return f"{c_return_type} {blas_macro}({blas_name})({c_args});\n"
--- 
+--
 2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch b/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
index b9e521f3..537c4f6d 100644
--- a/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
+++ b/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
@@ -24,28 +24,27 @@ index b43016c027..cbd80252b1 100644
  import itertools
  import platform
 +import sys
- 
+
  import numpy as np
  from numpy.testing import (assert_equal, assert_almost_equal,
 @@ -37,6 +38,8 @@ try:
  except ImportError:
      CONFIG = None
- 
+
 +IS_WASM = (sys.platform == "emscripten" or platform.machine() in ["wasm32", "wasm64"])
 +
- 
+
  def _random_hermitian_matrix(n, posdef=False, dtype=float):
      "Generate random sym/hermitian array of the given size n"
 @@ -1179,6 +1182,9 @@ class TestSVD_GESVD(TestSVD_GESDD):
      lapack_driver = 'gesvd'
- 
- 
+
+
 +# Allocating an array of such a size leads to _ArrayMemoryError(s)
 +# since the maximum memory that can be in 32-bit (WASM) is 4GB
 +@pytest.mark.skipif(IS_WASM, reason="out of memory in WASM")
  @pytest.mark.fail_slow(5)
  def test_svd_gesdd_nofegfault():
      # svd(a) with {U,VT}.size > INT_MAX does not segfault
--- 
+--
 2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch b/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
index a80ca320..6e17b59a 100644
--- a/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
+++ b/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
@@ -33,7 +33,7 @@ index cfaa927139..44c63fa526 100644
 @@ -128,8 +128,14 @@ py3.extension_module('_odepack',
    subdir: 'scipy/integrate'
  )
- 
+
 +vode_module = custom_target('vode_module',
 +  output: ['_vode-f2pywrappers.f', '_vodemodule.c'],
 +  input: 'vode.pyf',
@@ -49,7 +49,7 @@ index cfaa927139..44c63fa526 100644
 @@ -139,8 +145,14 @@ py3.extension_module('_vode',
    subdir: 'scipy/integrate'
  )
- 
+
 +lsoda_module = custom_target('lsoda_module',
 +  output: ['_lsoda-f2pywrappers.f', '_lsodamodule.c'],
 +  input: 'lsoda.pyf',
@@ -65,7 +65,7 @@ index cfaa927139..44c63fa526 100644
 @@ -150,8 +162,14 @@ py3.extension_module('_lsoda',
    subdir: 'scipy/integrate'
  )
- 
+
 +_dop_module = custom_target('_dop_module',
 +  output: ['_dop-f2pywrappers.f', '_dopmodule.c'],
 +  input: 'dop.pyf',
@@ -81,7 +81,7 @@ index cfaa927139..44c63fa526 100644
 @@ -169,8 +187,14 @@ py3.extension_module('_test_multivariate',
    install_tag: 'tests'
  )
- 
+
 +_test_odeint_banded_module = custom_target('_test_odeint_banded_module',
 +  output: ['_test_odeint_bandedmodule.c', '_test_odeint_banded-f2pywrappers.f'],
 +  input: 'tests/test_odeint_banded.pyf',
@@ -101,7 +101,7 @@ index 69ec25f6af..38dd2a8cc3 100644
 @@ -143,9 +143,15 @@ py3.extension_module('_fitpack',
    subdir: 'scipy/interpolate'
  )
- 
+
 +dfitpack_module = custom_target('dfitpack_module',
 +  output: ['_dfitpack-f2pywrappers.f', '_dfitpackmodule.c'],
 +  input: 'src/dfitpack.pyf',
@@ -140,7 +140,7 @@ index a0857848a2..ff47bde52e 100644
 @@ -144,30 +144,6 @@ fortranobject_dep = declare_dependency(
    compile_args: _f2py_c_args,
  )
- 
+
 -f2py = find_program('f2py')
 -# It should be quite rare for the `f2py` executable to not be the one from
 -# `numpy` installed in the Python env we are building for (unless we are
@@ -175,7 +175,7 @@ index 50d62ef68b..6cef85027a 100644
 @@ -92,12 +92,18 @@ py3.extension_module('_zeros',
    subdir: 'scipy/optimize'
  )
- 
+
 +lbfgsb_module = custom_target('lbfgsb_module',
 +  output: ['_lbfgsb-f2pywrappers.f', '_lbfgsbmodule.c'],
 +  input: 'lbfgsb_src/lbfgsb.pyf',
@@ -195,7 +195,7 @@ index 50d62ef68b..6cef85027a 100644
 @@ -120,6 +126,12 @@ py3.extension_module('_moduleTNC',
    subdir: 'scipy/optimize'
  )
- 
+
 +cobyla_module = custom_target('cobyla_module',
 +  output: ['_cobylamodule.c'],
 +  input: 'cobyla/cobyla.pyf',
@@ -209,7 +209,7 @@ index 50d62ef68b..6cef85027a 100644
 @@ -131,8 +143,14 @@ py3.extension_module('_cobyla',
    subdir: 'scipy/optimize'
  )
- 
+
 +minpack2_module = custom_target('minpack2_module',
 +  output: ['_minpack2module.c'],
 +  input: 'minpack2/minpack2.pyf',
@@ -225,7 +225,7 @@ index 50d62ef68b..6cef85027a 100644
 @@ -142,8 +160,14 @@ py3.extension_module('_minpack2',
    subdir: 'scipy/optimize'
  )
- 
+
 +slsqp_module = custom_target('slsqp_module',
 +  output: ['_slsqpmodule.c'],
 +  input: 'slsqp/slsqp.pyf',
@@ -245,7 +245,7 @@ index 6714724958..df358df651 100644
 @@ -97,8 +97,14 @@ foreach ele: elements
      gnu_symbol_visibility: 'hidden',
    )
- 
+
 +  propack_module = custom_target('propack_module' + ele[0],
 +    output: [ele[0] + '-f2pywrappers.f', ele[0] + 'module.c'],
 +    input: ele[2],
@@ -265,7 +265,7 @@ index 358279a93b..7c973b1cf3 100644
 @@ -31,8 +31,14 @@ py3.extension_module('_ansari_swilk_statistics',
    subdir: 'scipy/stats'
  )
- 
+
 +mvn_module = custom_target('mvn_module',
 +  output: ['_mvn-f2pywrappers.f', '_mvnmodule.c'],
 +  input: 'mvn.pyf',
@@ -287,11 +287,11 @@ index b6bc02eb04..3da75c14d1 100644
  import re
  import subprocess
 +import sys
- 
- 
+
+
  # START OF CODE VENDORED FROM `numpy.distutils.from_template`
 @@ -283,7 +284,7 @@ def main():
- 
+
      # Now invoke f2py to generate the C API module file
      if args.infile.endswith(('.pyf.src', '.pyf')):
 -        p = subprocess.Popen(['f2py', fname_pyf,
@@ -299,6 +299,5 @@ index b6bc02eb04..3da75c14d1 100644
                              '--build-dir', outdir_abs], #'--quiet'],
                              stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                              cwd=os.getcwd())
--- 
+--
 2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch b/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
index 9f45ad86..f01ce6fc 100644
--- a/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
+++ b/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
@@ -17,12 +17,11 @@ index 82b813ea85..24bee0a21c 100644
 @@ -33,7 +33,7 @@ else
    scipy_import_dll_args = []
  endif
- 
+
 -sf_error_state_lib = shared_library('sf_error_state',
 +sf_error_state_lib = static_library('sf_error_state',
    ['sf_error_state.c'],
    include_directories: ['../_lib', '../_build_utils/src'],
    c_args: scipy_export_dll_args,
--- 
+--
 2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch b/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
index 56be63ec..12e3cbf1 100644
--- a/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
+++ b/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
@@ -18,7 +18,7 @@ index ae9e2466e1..e11626db0d 100644
 @@ -187,24 +187,6 @@ py3.extension_module('_test_multivariate',
    install_tag: 'tests'
  )
- 
+
 -_test_odeint_banded_module = custom_target('_test_odeint_banded_module',
 -  output: ['_test_odeint_bandedmodule.c', '_test_odeint_banded-f2pywrappers.f'],
 -  input: 'tests/test_odeint_banded.pyf',
@@ -39,7 +39,7 @@ index ae9e2466e1..e11626db0d 100644
 -
  subdir('_ivp')
  subdir('tests')
- 
+
 diff --git a/scipy/io/meson.build b/scipy/io/meson.build
 index d6fc6dc749..af04022208 100644
 --- a/scipy/io/meson.build
@@ -69,6 +69,5 @@ index d6fc6dc749..af04022208 100644
  py3.install_sources([
      '__init__.py',
      '_fortran.py',
--- 
+--
 2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch b/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
index e2ffa67b..f090254c 100644
--- a/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
+++ b/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
@@ -20,7 +20,7 @@ index 99d4886558..bf7256e605 100644
 @@ -2310,13 +2310,12 @@ function lange(norm,m,n,a,lda,work) result(n2)
       dimension(m+1),intent(cache,hide) :: work
  end function lange
- 
+
 -subroutine larfg(n, alpha, x, incx, tau, lx)
 +subroutine larfg(n, alpha, x, incx, tau)
      integer intent(in), check(n>=1) :: n
@@ -31,8 +31,7 @@ index 99d4886558..bf7256e605 100644
       intent(out) :: tau
 -    integer intent(hide),depend(x,n,incx),check(lx > (n-2)*incx) :: lx = len(x)
  end subroutine larfg
- 
+
  subroutine larf(side,m,n,v,incv,tau,c,ldc,work,lwork)
--- 
+--
 2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/test_scipy.py b/integration_tests/recipes/scipy/test_scipy.py
index ebd09bed..658eb87f 100644
--- a/integration_tests/recipes/scipy/test_scipy.py
+++ b/integration_tests/recipes/scipy/test_scipy.py
@@ -47,9 +47,8 @@ def test_binom_ppf(selenium):
 @pytest.mark.driver_timeout(40)
 @run_in_pyodide(packages=["pytest", "scipy-tests", "micropip"])
 async def test_scipy_pytest(selenium):
-    import pytest
-
     import micropip
+    import pytest
 
     await micropip.install("hypothesis")
 

From 611ed7b88c654fc417152f03917a4af630a1b5bb Mon Sep 17 00:00:00 2001
From: Gyeongjae Choi 
Date: Tue, 15 Oct 2024 12:17:01 +0000
Subject: [PATCH 12/71] exclude patchfile from codespell

---
 .pre-commit-config.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 713bbf64..5ba1b28d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -43,6 +43,8 @@ repos:
           [
             "--ignore-words-list",
             "ags,aray,asend,ba,classs,crate,falsy,feld,inflight,lits,nd,slowy,te,oint,conveniant",
+            "--skip",
+            "*.patch",
           ]
 
   - repo: https://github.com/pre-commit/mirrors-mypy

From 9ec8e60b35e3e18e3dca638df68c5fc7ef89e17d Mon Sep 17 00:00:00 2001
From: Gyeongjae Choi 
Date: Tue, 15 Oct 2024 12:17:48 +0000
Subject: [PATCH 13/71] [integration]


From f962cc49c200e8c745deead14f7601356840e3df Mon Sep 17 00:00:00 2001
From: Gyeongjae Choi 
Date: Tue, 15 Oct 2024 12:23:13 +0000
Subject: [PATCH 14/71] Remove integration tests from pre-commit check

---
 .pre-commit-config.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5ba1b28d..246e3b58 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,3 +1,4 @@
+exclude: (^integration_tests)
 default_language_version:
   python: "3.12"
 repos:

From 54efaccc757318a1dc48dfe3c01a8daa88623374 Mon Sep 17 00:00:00 2001
From: Gyeongjae Choi 
Date: Tue, 15 Oct 2024 12:24:50 +0000
Subject: [PATCH 15/71] Fix integration test [integration]

---
 .../recipes/libf2c/extras/make.inc            | 115 ++++++----
 .../libf2c/patches/0001-fix-arith.h.patch     |   5 +-
 .../patches/0002-fix-f2clibs-build.patch      |   3 +-
 .../0003-remove-redundant-symbols.patch       |   9 +-
 .../patches/0004-correct-return-types.patch   |   9 +-
 ...5-Remove-symbols-defined-in-OpenBLAS.patch |   3 +-
 .../patches/0006-adjust-ld-ar-ranlib.patch    |  14 +-
 .../0001-Add-Wno-return-type-flag.patch       |   5 +-
 ...ray-signature-with-scipy-expectation.patch |   5 +-
 ...-Fix-dstevr-in-special-lapack_defs.h.patch |   5 +-
 .../scipy/patches/0002-int-to-string.patch    |   3 +-
 .../scipy/patches/0003-gemm_-no-const.patch   |  19 +-
 .../patches/0004-make-int-return-values.patch |  77 +++----
 .../scipy/patches/0005-Fix-fitpack.patch      |   5 +-
 .../scipy/patches/0006-Fix-gees-calls.patch   |  15 +-
 ...-linalg-Remove-id_dist-Fortran-files.patch | 201 +++++++++---------
 ...0008-Mark-mvndst-functions-recursive.patch |  17 +-
 .../patches/0009-Make-sreorth-recursive.patch |  27 +--
 ...enblas-with-modules-that-require-f2c.patch |   2 +-
 ...chec-inline-if-then-endif-constructs.patch |   3 +-
 .../patches/0012-Remove-chla_transtype.patch  |   3 +-
 .../0013-Set-wrapper-return-type-to-int.patch |   3 +-
 .../patches/0014-Skip-svd_gesdd-test.patch    |  13 +-
 .../patches/0015-Remove-f2py-generators.patch |  33 +--
 ...-sf_error_state_lib-a-static-library.patch |   5 +-
 ...move-test-modules-that-fail-to-build.patch |   7 +-
 ...-Fix-lapack-larfg-function-signature.patch |   7 +-
 integration_tests/recipes/scipy/test_scipy.py |   3 +-
 28 files changed, 342 insertions(+), 274 deletions(-)

diff --git a/integration_tests/recipes/libf2c/extras/make.inc b/integration_tests/recipes/libf2c/extras/make.inc
index 2995eaa1..7eaae7b5 100644
--- a/integration_tests/recipes/libf2c/extras/make.inc
+++ b/integration_tests/recipes/libf2c/extras/make.inc
@@ -1,37 +1,80 @@
 # -*- Makefile -*-
-#################################################################### # LAPACK
-make include file. # # LAPACK, Version 3.2.1 # # June 2009 #
-#################################################################### # # See the
-INSTALL/ directory for more examples. # SHELL = /usr/bin/env sh # # The machine
-(platform) identifier to append to the library names # # WA for WebAssembly PLAT
-= _WA # # Modify the FORTRAN and OPTS definitions to refer to the # compiler and
-desired compiler options for your machine. NOOPT # refers to the compiler
-options desired when NO OPTIMIZATION is # selected. Define LOADER and LOADOPTS
-to refer to the loader # and desired load options for your machine. #
-####################################################### # This is used to
-compile C library #CC = gcc # inherit $CC from emmake # if no wrapping of the
-blas library is needed, uncomment next line #CC = gcc -DNO_BLAS_WRAP CFLAGS =
--O3 -I$(TOPDIR)/INCLUDE -fPIC -DNO_BLAS_WRAP LDFLAGS = -O3 LOADER = $(CC)
-LOADOPTS = NOOPT = -O0 -I$(TOPDIR)/INCLUDE -fPIC DRVCFLAGS = $(CFLAGS) F2CCFLAGS
-= $(CFLAGS)
-####################################################################### # #
-Timer for the SECOND and DSECND routines # # Default : SECOND and DSECND will
-use a call to the EXTERNAL FUNCTION ETIME # TIMER = EXT_ETIME # For RS6K :
-SECOND and DSECND will use a call to the EXTERNAL FUNCTION ETIME_ # TIMER =
-EXT_ETIME_ # For gfortran compiler: SECOND and DSECND will use a call to the
-INTERNAL FUNCTION ETIME # TIMER = INT_ETIME # If your Fortran compiler does not
-provide etime (like Nag Fortran Compiler, etc...) # SECOND and DSECND will use a
-call to the Fortran standard INTERNAL FUNCTION CPU_TIME TIMER = INT_CPU_TIME #
-If neither of this works...you can use the NONE value... In that case, SECOND
-and DSECND will always return 0 # TIMER = NONE # # The archiver and the flag(s)
-to use when building archive (library) # If you system has no ranlib, set RANLIB
-= echo. # ARCH = $(AR) ARCHFLAGS= cr #RANLIB = ranlib # # The location of BLAS
-library for linking the testing programs. # The target's machine-specific,
-optimized BLAS library should be # used whenever possible. # BLASLIB =
-../../blas$(PLAT).a # # Location of the extended-precision BLAS (XBLAS) Fortran
-library # used for building and testing extended-precision routines. The #
-relevant routines will be compiled and XBLAS will be linked only if # USEXBLAS
-is defined. # # USEXBLAS = Yes XBLASLIB = # XBLASLIB = -lxblas # # Names of
-generated libraries. # LAPACKLIB = lapack$(PLAT).a F2CLIB =
-../../F2CLIBS/libf2c.a TMGLIB = tmglib$(PLAT).a EIGSRCLIB = eigsrc$(PLAT).a
-LINSRCLIB = linsrc$(PLAT).a
+####################################################################
+#  LAPACK make include file.                                       #
+#  LAPACK, Version 3.2.1                                           #
+#  June 2009		                                               #
+####################################################################
+#
+# See the INSTALL/ directory for more examples.
+#
+SHELL = /usr/bin/env sh
+#
+#  The machine (platform) identifier to append to the library names
+#
+# WA for WebAssembly
+PLAT = _WA
+#
+#  Modify the FORTRAN and OPTS definitions to refer to the
+#  compiler and desired compiler options for your machine.  NOOPT
+#  refers to the compiler options desired when NO OPTIMIZATION is
+#  selected.  Define LOADER and LOADOPTS to refer to the loader
+#  and desired load options for your machine.
+#
+#######################################################
+# This is used to compile C library
+#CC        = gcc  # inherit $CC from emmake
+# if no wrapping of the blas library is needed, uncomment next line
+#CC        = gcc -DNO_BLAS_WRAP
+CFLAGS    = -O3 -I$(TOPDIR)/INCLUDE -fPIC -DNO_BLAS_WRAP
+LDFLAGS	  = -O3
+LOADER    = $(CC)
+LOADOPTS  =
+NOOPT     = -O0 -I$(TOPDIR)/INCLUDE -fPIC
+DRVCFLAGS = $(CFLAGS)
+F2CCFLAGS = $(CFLAGS)
+#######################################################################
+
+#
+# Timer for the SECOND and DSECND routines
+#
+# Default : SECOND and DSECND will use a call to the EXTERNAL FUNCTION ETIME
+# TIMER    = EXT_ETIME
+# For RS6K : SECOND and DSECND will use a call to the EXTERNAL FUNCTION ETIME_
+# TIMER    = EXT_ETIME_
+# For gfortran compiler: SECOND and DSECND will use a call to the INTERNAL FUNCTION ETIME
+# TIMER    = INT_ETIME
+# If your Fortran compiler does not provide etime (like Nag Fortran Compiler, etc...)
+# SECOND and DSECND will use a call to the Fortran standard INTERNAL FUNCTION CPU_TIME
+TIMER    = INT_CPU_TIME
+# If neither of this works...you can use the NONE value... In that case, SECOND and DSECND will always return 0
+# TIMER     = NONE
+#
+#  The archiver and the flag(s) to use when building archive (library)
+#  If you system has no ranlib, set RANLIB = echo.
+#
+ARCH     = $(AR)
+ARCHFLAGS= cr
+#RANLIB   = ranlib
+#
+#  The location of BLAS library for linking the testing programs.
+#  The target's machine-specific, optimized BLAS library should be
+#  used whenever possible.
+#
+BLASLIB      = ../../blas$(PLAT).a
+#
+#  Location of the extended-precision BLAS (XBLAS) Fortran library
+#  used for building and testing extended-precision routines.  The
+#  relevant routines will be compiled and XBLAS will be linked only if
+#  USEXBLAS is defined.
+#
+# USEXBLAS    = Yes
+XBLASLIB     =
+# XBLASLIB    = -lxblas
+#
+#  Names of generated libraries.
+#
+LAPACKLIB    = lapack$(PLAT).a
+F2CLIB       = ../../F2CLIBS/libf2c.a
+TMGLIB       = tmglib$(PLAT).a
+EIGSRCLIB    = eigsrc$(PLAT).a
+LINSRCLIB    = linsrc$(PLAT).a
diff --git a/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch b/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch
index 04d995a1..7773825a 100644
--- a/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch
+++ b/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch
@@ -22,8 +22,9 @@ index 0a3ed0d..a473ed8 100644
 -	rm -f a.out arithchk.o
 +	node a.out.js >arith.h
 +	rm -f a.out.js a.out.wasm
-
+ 
  check:
  	xsum Notice README abort_.c arithchk.c backspac.c c_abs.c c_cos.c \
---
+-- 
 2.25.1
+
diff --git a/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch b/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch
index b7c68721..89d94e5d 100644
--- a/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch
+++ b/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch
@@ -26,5 +26,6 @@ index a473ed8..e51d826 100644
  ## Under Solaris (and other systems that do not understand ld -x),
  ## omit -x in the ld line above.
  ## If your system does not have the ld command, comment out
---
+-- 
 2.25.1
+
diff --git a/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch b/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch
index 65a730a4..bfd7257f 100644
--- a/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch
+++ b/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch
@@ -20,14 +20,15 @@ index 5f1eb22..32e669b 100644
 @@ -48,9 +48,9 @@ include ../make.inc
  #
  #######################################################################
-
+ 
 -ALLAUX = maxloc.o ilaenv.o ieeeck.o lsamen.o xerbla.o xerbla_array.o iparmq.o	\
 +ALLAUX = maxloc.o ilaenv.o ieeeck.o lsamen.o iparmq.o	\
      ilaprec.o ilatrans.o ilauplo.o iladiag.o chla_transtype.o \
 -    ../INSTALL/ilaver.o ../INSTALL/lsame.o
 +    ../INSTALL/ilaver.o
-
+ 
  ALLXAUX =
-
---
+ 
+-- 
 2.25.1
+
diff --git a/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch b/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch
index 6b05ba0e..5d95f705 100644
--- a/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch
+++ b/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch
@@ -48,9 +48,9 @@ index 8d92a63..54c4ff1 100644
 @@ -28,11 +28,11 @@ extern
  extern "C" {
  #endif
-
+ 
 - VOID
-+
++ 
  #ifdef KR_headers
 -s_cat(lp, rpp, rnp, np, ll) char *lp, *rpp[]; ftnint rnp[], *np; ftnlen ll;
 +int s_cat(lp, rpp, rnp, np, ll) char *lp, *rpp[]; ftnint rnp[], *np; ftnlen ll;
@@ -66,7 +66,7 @@ index 9dacfc7..8d8963f 100644
 +++ b/F2CLIBS/libf2c/s_copy.c
 @@ -12,9 +12,9 @@ extern "C" {
  /* assign strings:  a = b */
-
+ 
  #ifdef KR_headers
 -VOID s_copy(a, b, la, lb) register char *a, *b; ftnlen la, lb;
 +int s_copy(a, b, la, lb) register char *a, *b; ftnlen la, lb;
@@ -76,5 +76,6 @@ index 9dacfc7..8d8963f 100644
  #endif
  {
  	register char *aend, *bend;
---
+-- 
 2.25.1
+
diff --git a/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch b/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch
index 69c602ec..7dce211b 100644
--- a/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch
+++ b/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch
@@ -22,5 +22,6 @@ index 57eff0d..136050f 100644
  REAL =	r_abs.o r_acos.o r_asin.o r_atan.o r_atn2.o r_cnjg.o r_cos.o\
  	r_cosh.o r_dim.o r_exp.o r_imag.o r_int.o\
  	r_lg10.o r_log.o r_mod.o r_nint.o r_sign.o\
---
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch b/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch
index 29b7c275..336f3761 100644
--- a/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch
+++ b/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch
@@ -4,30 +4,30 @@ Index: CLAPACK-3.2.1/F2CLIBS/libf2c/Makefile
 +++ CLAPACK-3.2.1/F2CLIBS/libf2c/Makefile
 @@ -70,8 +70,8 @@ OFILES = $(MISC) $(POW) $(CX) $(DCX) $(R
  all: f2c.h signal1.h sysdep1.h libf2c.a clapack_install
-
+ 
  libf2c.a: $(OFILES)
 -	ar r libf2c.a $?
 -	-ranlib libf2c.a
 +	$(ARCH) r libf2c.a $?
 +	$(RANLIB) libf2c.a
-
+ 
  ## Shared-library variant: the following rule works on Linux
  ## systems.  Details are system-dependent.  Under Linux, -fPIC
 @@ -80,7 +80,7 @@ libf2c.a: $(OFILES)
  ## of "cc -shared".
-
+ 
  libf2c.so: $(OFILES)
 -	cc -shared -o libf2c.so $(OFILES)
 +	$(CC) -shared -o libf2c.so $(OFILES)
-
+ 
  ### If your system lacks ranlib, you don't need it; see README.
-
+ 
 @@ -117,7 +117,7 @@ sysdep1.h: sysdep1.h0
-
+ 
  install: libf2c.a
  	cp libf2c.a $(LIBDIR)
 -	-ranlib $(LIBDIR)/libf2c.a
 +	$(RANLIB) $(LIBDIR)/libf2c.a
-
+ 
  clapack_install: libf2c.a
  	mv libf2c.a ..
diff --git a/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch b/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch
index af738b5c..ae57a81a 100644
--- a/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch
+++ b/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch
@@ -21,8 +21,9 @@ index 5f787a9c..6890046a 100644
  # Flags for POWER8 are defined in Makefile.power. Don't modify COMMON_OPT
 -# COMMON_OPT = -O2
 +COMMON_OPT = -O2 -Wno-return-type
-
+ 
  # gfortran option for LAPACK to improve thread-safety
  # It is enabled by default in Makefile.system for gfortran
---
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch b/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
index d65f0513..d7ba240d 100644
--- a/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
+++ b/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
@@ -12,7 +12,7 @@ index fe7d6d898..74d3ca96a 100644
 --- a/lapack-netlib/SRC/xerbla_array.c
 +++ b/lapack-netlib/SRC/xerbla_array.c
 @@ -600,7 +600,7 @@ array.f"> */
-
+ 
  /*  ===================================================================== */
  /* Subroutine */ void xerbla_array_(char *srname_array__, integer *
 -	srname_len__, integer *info, integer srname_array_len)
@@ -20,5 +20,6 @@ index fe7d6d898..74d3ca96a 100644
  {
      /* System generated locals */
      integer i__1, i__2, i__3;
---
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch b/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
index ed81ec94..ca6d80a0 100644
--- a/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
+++ b/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
@@ -17,7 +17,7 @@ index 0d20ba1ca..d4325f71f 100644
                                double *work, CBLAS_INT *lwork, CBLAS_INT *iwork, CBLAS_INT *liwork,
 -                              CBLAS_INT *info, size_t jobz_len, size_t range_len);
 +                              CBLAS_INT *info);
-
+ 
  static void c_dstevr(char *jobz, char *range, CBLAS_INT *n, double *d, double *e,
                       double *vl, double *vu, CBLAS_INT *il, CBLAS_INT *iu, double *abstol,
                       CBLAS_INT *m, double *w, double *z, CBLAS_INT *ldz, CBLAS_INT *isuppz,
@@ -27,5 +27,6 @@ index 0d20ba1ca..d4325f71f 100644
 -                      1, 1);
 +                      w, z, ldz, isuppz, work, lwork, iwork, liwork, info);
  }
---
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0002-int-to-string.patch b/integration_tests/recipes/scipy/patches/0002-int-to-string.patch
index 0467762e..7a172cb2 100644
--- a/integration_tests/recipes/scipy/patches/0002-int-to-string.patch
+++ b/integration_tests/recipes/scipy/patches/0002-int-to-string.patch
@@ -24,5 +24,6 @@ index 7e180e4f8..b940bb702 100644
       1   i, lun, lunit, mesflg, ncpw, nch, nwds
        double precision r1, r2
        dimension msg(nmes)
---
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch b/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch
index c975e17f..3840f745 100644
--- a/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch
+++ b/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch
@@ -18,9 +18,9 @@ index dfc0516ac..92d7d7d6b 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h
 @@ -262,9 +262,9 @@ extern void    ccheck_tempv(int, singlecomplex *);
-
+ 
  /*! \brief BLAS */
-
+ 
 -extern int cgemm_(const char*, const char*, const int*, const int*, const int*,
 -                  const singlecomplex*, const singlecomplex*, const int*, const singlecomplex*,
 -		  const int*, const singlecomplex*, singlecomplex*, const int*);
@@ -35,9 +35,9 @@ index 3b5aa509f..1305641bd 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h
 @@ -260,9 +260,9 @@ extern void    dcheck_tempv(int, double *);
-
+ 
  /*! \brief BLAS */
-
+ 
 -extern int dgemm_(const char*, const char*, const int*, const int*, const int*,
 -                  const double*, const double*, const int*, const double*,
 -		  const int*, const double*, double*, const int*);
@@ -52,9 +52,9 @@ index 9bb6a38e7..b013962a4 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h
 @@ -259,9 +259,9 @@ extern void    scheck_tempv(int, float *);
-
+ 
  /*! \brief BLAS */
-
+ 
 -extern int sgemm_(const char*, const char*, const int*, const int*, const int*,
 -                  const float*, const float*, const int*, const float*,
 -		  const int*, const float*, float*, const int*);
@@ -69,9 +69,9 @@ index c6418d584..c5a2692be 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h
 @@ -262,9 +262,9 @@ extern void    zcheck_tempv(int, doublecomplex *);
-
+ 
  /*! \brief BLAS */
-
+ 
 -extern int zgemm_(const char*, const char*, const int*, const int*, const int*,
 -                  const doublecomplex*, const doublecomplex*, const int*, const doublecomplex*,
 -		  const int*, const doublecomplex*, doublecomplex*, const int*);
@@ -81,5 +81,6 @@ index c6418d584..c5a2692be 100644
  extern int ztrsv_(char*, char*, char*, int*, doublecomplex*, int*,
                    doublecomplex*, int*);
  extern int ztrsm_(char*, char*, char*, char*, int*, int*,
---
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch b/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch
index 89894034..5abeb4f0 100644
--- a/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch
+++ b/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch
@@ -45,7 +45,7 @@ index f35c94f984..1872d335aa 100644
 @@ -71,7 +71,7 @@ double_complex F_FUNC(wzdotu,WZDOTU)(CBLAS_INT *n, double_complex *zx, \
      return ret;
  }
-
+ 
 -void BLAS_FUNC(sladiv)(float *xr, float *xi, float *yr, float *yi, \
 +int BLAS_FUNC(sladiv)(float *xr, float *xi, float *yr, float *yi, \
      float *retr, float *reti);
@@ -54,7 +54,7 @@ index f35c94f984..1872d335aa 100644
 @@ -83,7 +83,7 @@ float_complex F_FUNC(wcladiv,WCLADIV)(float_complex *x, float_complex *y){
      return ret;
  }
-
+ 
 -void BLAS_FUNC(dladiv)(double *xr, double *xi, double *yr, double *yi, \
 +int BLAS_FUNC(dladiv)(double *xr, double *xi, double *yr, double *yi, \
      double *retr, double *reti);
@@ -63,41 +63,41 @@ index f35c94f984..1872d335aa 100644
 @@ -95,31 +95,31 @@ double_complex F_FUNC(wzladiv,WZLADIV)(double_complex *x, double_complex *y){
      return ret;
  }
-
+ 
 -void F_FUNC(cdotcwrp,WCDOTCWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
 +int F_FUNC(cdotcwrp,WCDOTCWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
          CBLAS_INT *incx, float_complex *cy, CBLAS_INT *incy){
      *ret = F_FUNC(wcdotc,WCDOTC)(n, cx, incx, cy, incy);
  }
-
+ 
 -void F_FUNC(zdotcwrp,WZDOTCWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
 +int F_FUNC(zdotcwrp,WZDOTCWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
          CBLAS_INT *incx, double_complex *zy, CBLAS_INT *incy){
      *ret = F_FUNC(wzdotc,WZDOTC)(n, zx, incx, zy, incy);
  }
-
+ 
 -void F_FUNC(cdotuwrp,CDOTUWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
 +int F_FUNC(cdotuwrp,CDOTUWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
          CBLAS_INT *incx, float_complex *cy, CBLAS_INT *incy){
      *ret = F_FUNC(wcdotu,WCDOTU)(n, cx, incx, cy, incy);
  }
-
+ 
 -void F_FUNC(zdotuwrp,ZDOTUWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
 +int F_FUNC(zdotuwrp,ZDOTUWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
          CBLAS_INT *incx, double_complex *zy, CBLAS_INT *incy){
      *ret = F_FUNC(wzdotu,WZDOTU)(n, zx, incx, zy, incy);
  }
-
+ 
 -void F_FUNC(cladivwrp,CLADIVWRP)(float_complex *ret, float_complex *x, float_complex *y){
 +int F_FUNC(cladivwrp,CLADIVWRP)(float_complex *ret, float_complex *x, float_complex *y){
      *ret = F_FUNC(wcladiv,WCLADIV)(x, y);
  }
-
+ 
 -void F_FUNC(zladivwrp,ZLADIVWRP)(double_complex *ret, double_complex *x, double_complex *y){
 +int F_FUNC(zladivwrp,ZLADIVWRP)(double_complex *ret, double_complex *x, double_complex *y){
      *ret = F_FUNC(wzladiv,WZLADIV)(x, y);
  }
-
+ 
 diff --git a/scipy/integrate/_odepackmodule.c b/scipy/integrate/_odepackmodule.c
 index 0c8067e652..d085939859 100644
 --- a/scipy/integrate/_odepackmodule.c
@@ -105,18 +105,18 @@ index 0c8067e652..d085939859 100644
 @@ -156,17 +156,17 @@ static PyObject *odepack_error;
      #endif
  #endif
-
+ 
 -typedef void lsoda_f_t(F_INT *n, double *t, double *y, double *ydot);
 +typedef int lsoda_f_t(F_INT *n, double *t, double *y, double *ydot);
  typedef int lsoda_jac_t(F_INT *n, double *t, double *y, F_INT *ml, F_INT *mu,
                          double *pd, F_INT *nrowpd);
-
+ 
 -void LSODA(lsoda_f_t *f, F_INT *neq, double *y, double *t, double *tout, F_INT *itol,
 +int LSODA(lsoda_f_t *f, F_INT *neq, double *y, double *t, double *tout, F_INT *itol,
             double *rtol, double *atol, F_INT *itask, F_INT *istate, F_INT *iopt,
             double *rwork, F_INT *lrw, F_INT *iwork, F_INT *liw, lsoda_jac_t *jac,
             F_INT *jt);
-
+ 
  /*
 -void ode_function(int *n, double *t, double *y, double *ydot)
 +int ode_function(int *n, double *t, double *y, double *ydot)
@@ -126,7 +126,7 @@ index 0c8067e652..d085939859 100644
 @@ -175,7 +175,7 @@ void ode_function(int *n, double *t, double *y, double *ydot)
  }
  */
-
+ 
 -void
 +int
  ode_function(F_INT *n, double *t, double *y, double *ydot)
@@ -138,8 +138,8 @@ index c806e33fbf..c4b822eb92 100644
 +++ b/scipy/odr/__odrpack.c
 @@ -13,7 +13,7 @@
  #include "odrpack.h"
-
-
+ 
+ 
 -void F_FUNC(dodrc,DODRC)(void (*fcn)(F_INT *n, F_INT *m, F_INT *np, F_INT *nq, F_INT *ldn, F_INT *ldm,
 +void F_FUNC(dodrc,DODRC)(int (*fcn)(F_INT *n, F_INT *m, F_INT *np, F_INT *nq, F_INT *ldn, F_INT *ldm,
              F_INT *ldnp, double *beta, double *xplusd, F_INT *ifixb, F_INT *ifixx,
@@ -152,7 +152,7 @@ index c1dc7fcf8f..d1903db4a6 100644
 @@ -23,10 +23,10 @@ at the top-level directory.
  #include 
  #include "slu_cdefs.h"
-
+ 
 -extern void cswap_(int *, singlecomplex [], int *, singlecomplex [], int *);
 -extern void caxpy_(int *, singlecomplex *, singlecomplex [], int *, singlecomplex [], int *);
 -extern void ccopy_(int *, singlecomplex [], int *, singlecomplex [], int *);
@@ -171,10 +171,10 @@ index 4e2654e8ac..d5b955d40e 100644
 @@ -26,7 +26,7 @@ at the top-level directory.
  int num_drop_U;
  #endif
-
+ 
 -extern void scopy_(int *, float [], int *, float [], int *);
 +extern int scopy_(int *, float [], int *, float [], int *);
-
+ 
  #if 0
  static float *A;  /* used in _compare_ only */
 diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h
@@ -182,9 +182,9 @@ index 5afc93b5d9..7ac5f80fb9 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h
 @@ -3,6 +3,9 @@
-
+ 
  #include 
-
+ 
 +#include "f2c.h"
 +
 +
@@ -198,7 +198,7 @@ index 1395752d4c..7f5538140d 100644
 @@ -21,6 +21,8 @@ at the top-level directory.
   */
  #include "slu_sdefs.h"
-
+ 
 +extern float slangs(char *, SuperMatrix *);
 +
  /*! \brief
@@ -207,10 +207,10 @@ index 1395752d4c..7f5538140d 100644
 @@ -377,8 +379,6 @@ sgssvx(superlu_options_t *options, SuperMatrix *A, int *perm_c, int *perm_r,
      double    t0;      /* temporary time */
      double    *utime;
-
+ 
 -    /* External functions */
 -    extern float slangs(char *, SuperMatrix *);
-
+ 
      Bstore = B->Store;
      Xstore = X->Store;
 @@ -573,7 +573,8 @@ printf("dgssvx: Fact=%4d, Trans=%4d, equed=%c\n",
@@ -230,21 +230,21 @@ index 67e83bcc77..e5757d5c4d 100644
 @@ -28,7 +28,10 @@ at the top-level directory.
  #ifndef DCOMPLEX_INCLUDE
  #define DCOMPLEX_INCLUDE
-
+ 
 -typedef struct { double r, i; } doublecomplex;
 +#include"scipy_slu_config.h"
 +
 +// defined in clapack
 +//typedef struct { double r, i; } doublecomplex;
-
-
+ 
+ 
  /* Macro definitions */
 diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
 index 83be8c971f..047a07ce9c 100644
 --- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
 +++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
 @@ -27,8 +27,9 @@ at the top-level directory.
-
+ 
  #ifndef SCOMPLEX_INCLUDE
  #define SCOMPLEX_INCLUDE
 -
@@ -252,8 +252,8 @@ index 83be8c971f..047a07ce9c 100644
 +#include"scipy_slu_config.h"
 +// defined in  CLAPACK
 +//typedef struct { float r, i; } singlecomplex;
-
-
+ 
+ 
  /* Macro definitions */
 diff --git a/scipy/sparse/linalg/_dsolve/_superlu_utils.c b/scipy/sparse/linalg/_dsolve/_superlu_utils.c
 index 49b928a431..0822687719 100644
@@ -262,13 +262,13 @@ index 49b928a431..0822687719 100644
 @@ -243,12 +243,12 @@ int input_error(char *srname, int *info)
   * Stubs for Harwell Subroutine Library functions that SuperLU tries to call.
   */
-
+ 
 -void mc64id_(int *a)
 +int mc64id_(int *a)
  {
      superlu_python_module_abort("chosen functionality not available");
  }
-
+ 
 -void mc64ad_(int *a, int *b, int *c, int d[], int e[], double f[],
 +int mc64ad_(int *a, int *b, int *c, int d[], int e[], double f[],
  	     int *g, int h[], int *i, int j[], int *k, double l[],
@@ -281,8 +281,8 @@ index 5eb0bb1b3d..81a6efafb9 100644
 @@ -1,16 +1,16 @@
 -c
 +
- c\SCCS Information: @(#)
- c FILE: debug.h   SID: 2.3   DATE OF SID: 11/16/95   RELEASE: 2
+ c\SCCS Information: @(#) 
+ c FILE: debug.h   SID: 2.3   DATE OF SID: 11/16/95   RELEASE: 2 
  c
  c     %---------------------------------%
  c     | See debug.doc for documentation |
@@ -291,7 +291,7 @@ index 5eb0bb1b3d..81a6efafb9 100644
 -     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
 -     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
 -     &         mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd
--      common /debug/
+-      common /debug/ 
 -     &         logfil, ndigit, mgetv0,
 -     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
 -     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
@@ -310,8 +310,8 @@ index 66a8e9f87f..81d49c3bd2 100644
 --- a/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h
 +++ b/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h
 @@ -5,17 +5,17 @@ c
- c\SCCS Information: @(#)
- c FILE: stat.h   SID: 2.2   DATE OF SID: 11/16/95   RELEASE: 2
+ c\SCCS Information: @(#) 
+ c FILE: stat.h   SID: 2.2   DATE OF SID: 11/16/95   RELEASE: 2 
  c
 -      real       t0, t1, t2, t3, t4, t5
 -      save       t0, t1, t2, t3, t4, t5
@@ -323,7 +323,7 @@ index 66a8e9f87f..81d49c3bd2 100644
 -     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
 -     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
 -     &           tmvopx, tmvbx, tgetv0, titref, trvec
--      common /timing/
+-      common /timing/ 
 -     &           nopx, nbx, nrorth, nitref, nrstrt,
 -     &           tsaupd, tsaup2, tsaitr, tseigt, tsgets, tsapps, tsconv,
 -     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
@@ -340,5 +340,6 @@ index 66a8e9f87f..81d49c3bd2 100644
 +c     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
 +c     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
 +c     &           tmvopx, tmvbx, tgetv0, titref, trvec
---
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch b/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch
index ab621ea1..1df3145c 100644
--- a/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch
+++ b/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch
@@ -62,7 +62,7 @@ index f02569a40..1e4d65724 100644
 +      evapol = f
        return
        end
-
+ 
 diff --git a/scipy/interpolate/fitpack/fprati.f b/scipy/interpolate/fitpack/fprati.f
 index 71c57eb01..97b5851df 100644
 --- a/scipy/interpolate/fitpack/fprati.f
@@ -107,5 +107,6 @@ index 02b00da6a..6024a0476 100644
    10  continue
        return
        end
---
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch b/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch
index 058469f3..feabf913 100644
--- a/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch
+++ b/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch
@@ -14,24 +14,25 @@ index 04037fdca..3686cea86 100644
 @@ -1196,8 +1196,8 @@ subroutine gees(compute_v,sort_t,select,n,a,nrows,sdim,w,vs,
      !  A = Z * T * Z^H  -- a complex matrix is in Schur form if it is upper
      !  triangular
-
+ 
 -    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,w,vs,&ldvs,work,&lwork,rwork,bwork,&info,1,1)
 -    callprotoargument char*,char*,F_INT(*)(*),F_INT*,*,F_INT*,F_INT*,*,*,F_INT*,*,F_INT*,*,F_INT*,F_INT*,F_INT,F_INT
 +    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,w,vs,&ldvs,work,&lwork,rwork,bwork,&info)
 +    callprotoargument char*,char*,F_INT(*)(*),F_INT*,*,F_INT*,F_INT*,*,*,F_INT*,*,F_INT*,*,F_INT*,F_INT*
-
+ 
      use gees__user__routines
-
+ 
 @@ -1226,8 +1226,8 @@ subroutine gees(compute_v,sort_t,select,n,a,nrows,sdim,wr,wi,v
      !  A = Z * T * Z^H  -- a real matrix is in Schur form if it is upper quasi-
      !  triangular with 1x1 and 2x2 blocks.
-
+ 
 -    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,wr,wi,vs,&ldvs,work,&lwork,bwork,&info,1,1)
 -    callprotoargument char*,char*,F_INT(*)(*,*),F_INT*,*,F_INT*,F_INT*,*,*,*,F_INT*,*,F_INT*,F_INT*,F_INT*,F_INT,F_INT
 +    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,wr,wi,vs,&ldvs,work,&lwork,bwork,&info)
 +    callprotoargument char*,char*,F_INT(*)(*,*),F_INT*,*,F_INT*,F_INT*,*,*,*,F_INT*,*,F_INT*,F_INT*,F_INT*
-
+ 
      use gees__user__routines
-
---
+ 
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch b/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
index b13156ca..e3a57c5b 100644
--- a/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
+++ b/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
@@ -134,11 +134,11 @@ index 4417af39dc..4bdbdf9750 100644
 @@ -140,7 +140,7 @@ ignore_missing_imports = True
  [mypy-scipy.linalg._solve_toeplitz]
  ignore_missing_imports = True
-
+ 
 -[mypy-scipy.linalg._interpolative]
 +[mypy-scipy.linalg._decomp_interpolative]
  ignore_missing_imports = True
-
+ 
  [mypy-scipy.optimize._group_columns]
 diff --git a/scipy/linalg/_decomp_interpolative.pyx b/scipy/linalg/_decomp_interpolative.pyx
 new file mode 100644
@@ -3843,36 +3843,36 @@ index b91cdd63a..f946b059f 100644
 -
 -# Python module for interfacing with `id_dist`.
 +#  ******************************************************************************
-
+ 
  r"""
  ======================================================================
  Interpolative matrix decomposition (:mod:`scipy.linalg.interpolative`)
  ======================================================================
-
+ 
 -.. moduleauthor:: Kenneth L. Ho 
 -
  .. versionadded:: 0.13
-
+ 
 +.. versionchanged:: 1.15.0
 +    The underlying algorithms have been ported to Python from the original Fortran77
 +    code. See references below for more details.
 +
  .. currentmodule:: scipy.linalg.interpolative
-
+ 
  An interpolative decomposition (ID) of a matrix :math:`A \in
 @@ -94,7 +94,7 @@ Main functionality:
     estimate_spectral_norm_diff
     estimate_rank
-
+ 
 -Support functions:
 +Following support functions are deprecated and will be removed in SciPy 1.17.0:
-
+ 
  .. autosummary::
     :toctree: generated/
 @@ -106,16 +106,13 @@ Support functions:
  References
  ==========
-
+ 
 -This module uses the ID software package [1]_ by Martinsson, Rokhlin,
 -Shkolnisky, and Tygert, which is a Fortran library for computing IDs
 -using various algorithms, including the rank-revealing QR approach of
@@ -3884,17 +3884,17 @@ index b91cdd63a..f946b059f 100644
 +Rokhlin, Shkolnisky, and Tygert, which is a Fortran library for computing IDs using
 +various algorithms, including the rank-revealing QR approach of [2]_ and the more
 +recent randomized methods described in [3]_, [4]_, and [5]_.
-
+ 
 -We advise the user to consult also the `documentation for the ID package
 -`_.
 +We advise the user to consult also the documentation for the `ID package
 +`_.
-
+ 
  .. [1] P.G. Martinsson, V. Rokhlin, Y. Shkolnisky, M. Tygert. "ID: a
      software package for low-rank approximation of matrices via interpolative
 @@ -356,25 +353,8 @@ depending on the representation. The parameter ``eps`` controls the definition
  of the numerical rank.
-
+ 
  Finally, the random number generation required for all randomized routines can
 -be controlled via :func:`scipy.linalg.interpolative.seed`. To reset the seed
 -values to their original values, use:
@@ -3917,23 +3917,23 @@ index b91cdd63a..f946b059f 100644
 -where ``n`` is the number of random numbers to generate.
 +be controlled via providing NumPy pseudo-random generators with a fixed seed. See
 +:class:`numpy.random.Generator` and :func:`numpy.random.default_rng` for more details.
-
+ 
  Remarks
  -------
 @@ -385,9 +365,9 @@ backend routine.
-
+ 
  """
-
+ 
 -import scipy.linalg._interpolative_backend as _backend
 +import scipy.linalg._decomp_interpolative as _backend
  import numpy as np
 -import sys
 +import warnings
-
+ 
  __all__ = [
      'estimate_rank',
 @@ -405,9 +385,18 @@ __all__ = [
-
+ 
  _DTYPE_ERROR = ValueError("invalid input dtype (input must be float64 or complex128)")
  _TYPE_ERROR = TypeError("invalid input type (must be array or LinearOperator)")
 -_32BIT_ERROR = ValueError("interpolative decomposition on 32-bit systems "
@@ -3951,11 +3951,11 @@ index b91cdd63a..f946b059f 100644
 +    else:
 +        A = np.ascontiguousarray(A)
 +    return A
-
-
+ 
+ 
  def _is_real(A):
 @@ -424,53 +413,29 @@ def _is_real(A):
-
+ 
  def seed(seed=None):
      """
 -    Seed the internal random number generator used in this ID package.
@@ -3979,7 +3979,7 @@ index b91cdd63a..f946b059f 100644
 -        initialize the generator.
 +    This function, historically, used to set the seed of the randomization algorithms
 +    used in the `scipy.linalg.interpolative` functions written in Fortran77.
-
+ 
 +    The library has been ported to Python and now the functions use the native NumPy
 +    generators and this function has no content and returns None. Thus this function
 +    should not be used and will be removed in SciPy version 1.17.0.
@@ -4003,8 +4003,8 @@ index b91cdd63a..f946b059f 100644
 -        _backend.id_srandi(rnd.rand(55))
 +    warnings.warn("`scipy.linalg.interpolative.seed` is deprecated and will be "
 +                  "removed in SciPy 1.17.0.", DeprecationWarning, stacklevel=3)
-
-
+ 
+ 
  def rand(*shape):
      """
 -    Generate standard uniform pseudorandom numbers via a very efficient lagged
@@ -4012,7 +4012,7 @@ index b91cdd63a..f946b059f 100644
 +    This function, historically, used to generate uniformly distributed random number
 +    for the randomization algorithms used in the `scipy.linalg.interpolative` functions
 +    written in Fortran77.
-
+ 
 -    This routine is used for all random number generation in this package and
 -    can affect ID and SVD results.
 +    The library has been ported to Python and now the functions use the native NumPy
@@ -4021,12 +4021,12 @@ index b91cdd63a..f946b059f 100644
 +
 +    If pseudo-random numbers are needed, NumPy pseudo-random generators should be used
 +    instead.
-
+ 
      Parameters
      ----------
 @@ -478,11 +443,13 @@ def rand(*shape):
          Shape of output array
-
+ 
      """
 -    # For details, see :func:`_backend.id_srand`, and :func:`_backend.id_srando`.
 -    return _backend.id_srand(np.prod(shape)).reshape(shape)
@@ -4034,13 +4034,13 @@ index b91cdd63a..f946b059f 100644
 +                  "removed in SciPy 1.17.0.", DeprecationWarning, stacklevel=3)
 +    rng = np.random.default_rng()
 +    return rng.uniform(low=0., high=1.0, size=shape)
-
-
+ 
+ 
 -def interp_decomp(A, eps_or_k, rand=True):
 +def interp_decomp(A, eps_or_k, rand=True, rng=None):
      """
      Compute ID of a matrix.
-
+ 
 @@ -546,6 +513,9 @@ def interp_decomp(A, eps_or_k, rand=True):
          Whether to use random sampling if `A` is of type :class:`numpy.ndarray`
          (randomized algorithms are always used if `A` is of type
@@ -4048,12 +4048,12 @@ index b91cdd63a..f946b059f 100644
 +    rng : :class:`numpy.random.Generator`
 +        NumPy generator for the randomization steps in the algorithm. If ``rand`` is
 +        ``False``, the argument is ignored.
-
+ 
      Returns
      -------
 @@ -562,57 +532,49 @@ def interp_decomp(A, eps_or_k, rand=True):
      real = _is_real(A)
-
+ 
      if isinstance(A, np.ndarray):
 +        A = _C_contiguous_copy(A)
          if eps_or_k < 1:
@@ -4124,7 +4124,7 @@ index b91cdd63a..f946b059f 100644
 +            return idx, proj
      else:
          raise _TYPE_ERROR
-
+ 
 @@ -648,9 +610,9 @@ def reconstruct_matrix_from_id(B, idx, proj):
          Reconstructed matrix.
      """
@@ -4134,20 +4134,20 @@ index b91cdd63a..f946b059f 100644
      else:
 -        return _backend.idz_reconid(B, idx + 1, proj)
 +        return _backend.idz_reconid(B, idx, proj)
-
-
+ 
+ 
  def reconstruct_interp_matrix(idx, proj):
 @@ -662,10 +624,8 @@ def reconstruct_interp_matrix(idx, proj):
-
+ 
          P = numpy.hstack([numpy.eye(proj.shape[0]), proj])[:,numpy.argsort(idx)]
-
+ 
 -    The original matrix can then be reconstructed from its skeleton matrix `B`
 -    via::
 -
 -        numpy.dot(B, P)
 +    The original matrix can then be reconstructed from its skeleton matrix ``B``
 +    via ``A = B @ P``
-
+ 
      See also :func:`reconstruct_matrix_from_id` and
      :func:`reconstruct_skel_matrix`.
 @@ -677,7 +637,7 @@ def reconstruct_interp_matrix(idx, proj):
@@ -4158,7 +4158,7 @@ index b91cdd63a..f946b059f 100644
 +        1D column index array.
      proj : :class:`numpy.ndarray`
          Interpolation coefficients.
-
+ 
 @@ -686,10 +646,17 @@ def reconstruct_interp_matrix(idx, proj):
      :class:`numpy.ndarray`
          Interpolation matrix.
@@ -4176,8 +4176,8 @@ index b91cdd63a..f946b059f 100644
 +    p[:, idx[krank:]] = proj[:, :]
 +
 +    return p
-
-
+ 
+ 
  def reconstruct_skel_matrix(A, k, idx):
 @@ -726,10 +693,7 @@ def reconstruct_skel_matrix(A, k, idx):
      :class:`numpy.ndarray`
@@ -4188,8 +4188,8 @@ index b91cdd63a..f946b059f 100644
 -    else:
 -        return _backend.idz_copycols(A, k, idx + 1)
 +    return A[:, idx[:k]]
-
-
+ 
+ 
  def id_to_svd(B, idx, proj):
 @@ -753,7 +717,7 @@ def id_to_svd(B, idx, proj):
      B : :class:`numpy.ndarray`
@@ -4199,7 +4199,7 @@ index b91cdd63a..f946b059f 100644
 +        1D column index array.
      proj : :class:`numpy.ndarray`
          Interpolation coefficients.
-
+ 
 @@ -766,14 +730,16 @@ def id_to_svd(B, idx, proj):
      V : :class:`numpy.ndarray`
          Right singular vectors.
@@ -4213,20 +4213,20 @@ index b91cdd63a..f946b059f 100644
 +        U, S, V = _backend.idz_id2svd(B, idx, proj)
 +
      return U, S, V
-
-
+ 
+ 
 -def estimate_spectral_norm(A, its=20):
 +def estimate_spectral_norm(A, its=20, rng=None):
      """
      Estimate spectral norm of a matrix by the randomized power method.
-
+ 
 @@ -788,6 +754,8 @@ def estimate_spectral_norm(A, its=20):
          `matvec` and `rmatvec` methods (to apply the matrix and its adjoint).
      its : int, optional
          Number of power method iterations.
 +    rng : :class:`numpy.random.Generator`
 +        NumPy generator for the randomization steps in the algorithm.
-
+ 
      Returns
      -------
 @@ -796,18 +764,14 @@ def estimate_spectral_norm(A, its=20):
@@ -4245,8 +4245,8 @@ index b91cdd63a..f946b059f 100644
      else:
 -        return _backend.idz_snorm(m, n, matveca, matvec, its=its)
 +        return _backend.idz_snorm(A, its=its, rng=rng)
-
-
+ 
+ 
 -def estimate_spectral_norm_diff(A, B, its=20):
 +def estimate_spectral_norm_diff(A, B, its=20, rng=None):
      """
@@ -4258,7 +4258,7 @@ index b91cdd63a..f946b059f 100644
          Number of power method iterations.
 +    rng : :class:`numpy.random.Generator`
 +        NumPy generator for the randomization steps in the algorithm.
-
+ 
      Returns
      -------
 @@ -835,30 +801,20 @@ def estimate_spectral_norm_diff(A, B, its=20):
@@ -4283,20 +4283,20 @@ index b91cdd63a..f946b059f 100644
 -        return _backend.idz_diffsnorm(
 -            m, n, matveca1, matveca2, matvec1, matvec2, its=its)
 +        return _backend.idz_diffsnorm(A, B, its=its, rng=rng)
-
-
+ 
+ 
 -def svd(A, eps_or_k, rand=True):
 +def svd(A, eps_or_k, rand=True, rng=None):
      """
      Compute SVD of a matrix via an ID.
-
+ 
      An SVD of a matrix `A` is a factorization::
-
+ 
 -        A = numpy.dot(U, numpy.dot(numpy.diag(S), V.conj().T))
 +        A = U @ np.diag(S) @ V.conj().T
-
+ 
      where `U` and `V` have orthonormal columns and `S` is nonnegative.
-
+ 
 @@ -889,35 +845,39 @@ def svd(A, eps_or_k, rand=True):
          Whether to use random sampling if `A` is of type :class:`numpy.ndarray`
          (randomized algorithms are always used if `A` is of type
@@ -4304,7 +4304,7 @@ index b91cdd63a..f946b059f 100644
 +    rng : :class:`numpy.random.Generator`
 +        NumPy generator for the randomization steps in the algorithm. If ``rand`` is
 +        ``False``, the argument is ignored.
-
+ 
      Returns
      -------
      U : :class:`numpy.ndarray`
@@ -4318,9 +4318,9 @@ index b91cdd63a..f946b059f 100644
 +        2D array right singular vectors.
      """
      from scipy.sparse.linalg import LinearOperator
-
+ 
      real = _is_real(A)
-
+ 
      if isinstance(A, np.ndarray):
 +        A = _C_contiguous_copy(A)
          if eps_or_k < 1:
@@ -4395,8 +4395,8 @@ index b91cdd63a..f946b059f 100644
      else:
          raise _TYPE_ERROR
      return U, S, V
-
-
+ 
+ 
 -def estimate_rank(A, eps):
 +def estimate_rank(A, eps, rng=None):
      """
@@ -4408,12 +4408,12 @@ index b91cdd63a..f946b059f 100644
          Relative error for numerical rank definition.
 +    rng : :class:`numpy.random.Generator`
 +        NumPy generator for the randomization steps in the algorithm.
-
+ 
      Returns
      -------
 @@ -996,20 +949,19 @@ def estimate_rank(A, eps):
      real = _is_real(A)
-
+ 
      if isinstance(A, np.ndarray):
 +        A = _C_contiguous_copy(A)
          if real:
@@ -4442,9 +4442,9 @@ index cc208092e..777edd008 100644
 --- a/scipy/linalg/meson.build
 +++ b/scipy/linalg/meson.build
 @@ -111,57 +111,15 @@ py3.extension_module('_flapack',
-
+ 
  # TODO: cblas/clapack are built *only* for ATLAS. Why? Is it still needed?
-
+ 
 -# id_dist contains a copy of FFTPACK, which has type mismatch warnings
 -# that are hard to fix. This code is terrible and noisy during the build,
 -# silence it completely.
@@ -4504,7 +4504,7 @@ index cc208092e..777edd008 100644
 -  link_language: 'fortran',
    subdir: 'scipy/linalg'
  )
-
+ 
 @@ -278,7 +236,6 @@ python_sources = [
    '_decomp_schur.py',
    '_decomp_svd.py',
@@ -5080,7 +5080,7 @@ index 8bcece8c4..000000000
 -%
 -{\tt idd\_qrmatvec} & applies to a single vector the $Q$ matrix (or its
 -transpose) in the $QR$ decomposition of a matrix, as described by the
--output of routines {\tt iddp\_qrpiv} or {\tt iddr\_qrpiv}; to apply $Q$
+-output of routines {\tt iddp\_qrpiv} or {\tt iddr\_qrpiv}; to apply $Q$ 
 -(or its transpose) to several vectors efficiently, use routine
 -{\tt idd\_qrmatmat} instead & {\tt idd\_qrpiv.f} \\\hline
 -%
@@ -5251,7 +5251,7 @@ index 8bcece8c4..000000000
 -%
 -{\tt idz\_qrmatvec} & applies to a single vector the $Q$ matrix (or its
 -adjoint) in the $QR$ decomposition of a matrix, as described by the
--output of routines {\tt idzp\_qrpiv} or {\tt idzr\_qrpiv}; to apply $Q$
+-output of routines {\tt idzp\_qrpiv} or {\tt idzr\_qrpiv}; to apply $Q$ 
 -(or its adjoint) to several vectors efficiently, use routine
 -{\tt idz\_qrmatmat} instead & {\tt idz\_qrpiv.f} \\\hline
 -%
@@ -5373,7 +5373,7 @@ index 8bcece8c4..000000000
 -in the comments immediately following the declaration
 -of the subroutine's calling sequence.
 -This documentation describes the purpose of the routine,
--the input and output variables, and the required work arrays (if any).
+-the input and output variables, and the required work arrays (if any). 
 -This documentation also cites relevant references.
 -Please pay attention to the {\it N.B.}'s;
 -{\it N.B.} stands for {\it nota bene} (Latin for ``note well'')
@@ -5547,10 +5547,10 @@ index ac2638c23..000000000
 -%%
 -%% supertabular.dtx  (with options: `package')
 -%% Copyright (C) 1989-2004 Johannes Braams. All rights reserved.
--%%
+-%% 
 -%% This file was generated from file(s) of the supertabular package.
 -%% -----------------------------------------------------------------
--%%
+-%% 
 -%% It may be distributed and/or modified under the
 -%% conditions of the LaTeX Project Public License, either version 1.3
 -%% of this license or (at your option) any later version.
@@ -5558,18 +5558,18 @@ index ac2638c23..000000000
 -%%   http://www.latex-project.org/lppl.txt
 -%% and version 1.3 or later is part of all distributions of LaTeX
 -%% version 2003/12/01 or later.
--%%
+-%% 
 -%% This work has the LPPL maintenance status "maintained".
--%%
+-%% 
 -%% The Current Maintainer of this work is Johannes Braams.
--%%
+-%% 
 -%% This file may only be distributed together with a copy of the
 -%% supertabular package. You may however distribute the supertabular package
 -%% without such generated files.
--%%
+-%% 
 -%% The list of all files belonging to the supertabular package is
 -%% given in the file `manifest.txt.
--%%
+-%% 
 -%% The list of derived (unpacked) files belonging to the distribution
 -%% and covered by LPPL is defined by the unpacking scripts (with
 -%% extension .ins) which are part of the distribution.
@@ -15334,7 +15334,7 @@ index 2dc811148..000000000
 -        subroutine iddr_aid(m,n,a,krank,w,list,proj)
 -c
 -c       computes the ID of the matrix a, i.e., lists in list
--c       the indices of krank columns of a such that
+-c       the indices of krank columns of a such that 
 -c
 -c       a(j,list(k))  =  a(j,list(k))
 -c
@@ -21574,7 +21574,7 @@ index 679590d84..000000000
 -        IQ=IQ1
 -
 -        RETURN
--
+-  
 -C
 -C
 -C
@@ -21687,7 +21687,7 @@ index ddc56f7c7..95b83dfad 100644
  #   POSSIBILITY OF SUCH DAMAGE.
 -#******************************************************************************
 +#  ******************************************************************************
-
+ 
  import scipy.linalg.interpolative as pymatrixid
  import numpy as np
 @@ -36,8 +36,6 @@ from numpy.testing import (assert_, assert_allclose, assert_equal,
@@ -21696,13 +21696,13 @@ index ddc56f7c7..95b83dfad 100644
  from pytest import raises as assert_raises
 -import sys
 -_IS_32BIT = (sys.maxsize < 2**32)
-
-
+ 
+ 
  @pytest.fixture()
 @@ -45,6 +43,12 @@ def eps():
      yield 1e-12
-
-
+ 
+ 
 +@pytest.fixture()
 +def rng():
 +    rng = np.random.default_rng(1718313768084012)
@@ -21722,12 +21722,12 @@ index ddc56f7c7..95b83dfad 100644
 +    def test_real_id_fixed_precision(self, A, L, eps, rand, lin_op, rng):
          # Test ID routines on a Hilbert matrix.
          A_or_L = A if not lin_op else L
-
+ 
 -        k, idx, proj = pymatrixid.interp_decomp(A_or_L, eps, rand=rand)
 +        k, idx, proj = pymatrixid.interp_decomp(A_or_L, eps, rand=rand, rng=rng)
          B = pymatrixid.reconstruct_matrix_from_id(A[:, idx[:k]], idx, proj)
          assert_allclose(A, B, rtol=eps, atol=1e-08)
-
+ 
      @pytest.mark.parametrize(
          "rand,lin_op",
          [(False, False), (True, False), (True, True)])
@@ -21737,19 +21737,19 @@ index ddc56f7c7..95b83dfad 100644
 +    def test_real_id_fixed_rank(self, A, L, eps, rank, rand, lin_op, rng):
          k = rank
          A_or_L = A if not lin_op else L
-
+ 
 -        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand)
 +        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand, rng=rng)
          B = pymatrixid.reconstruct_matrix_from_id(A[:, idx[:k]], idx, proj)
          assert_allclose(A, B, rtol=eps, atol=1e-08)
-
+ 
      @pytest.mark.parametrize("rand,lin_op", [(False, False)])
      def test_real_id_skel_and_interp_matrices(
 -            self, A, L, eps, rank, rand, lin_op):
 +            self, A, L, eps, rank, rand, lin_op, rng):
          k = rank
          A_or_L = A if not lin_op else L
-
+ 
 -        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand)
 +        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand, rng=rng)
          P = pymatrixid.reconstruct_interp_matrix(idx, proj)
@@ -21764,12 +21764,12 @@ index ddc56f7c7..95b83dfad 100644
 -            pytest.xfail("bug in external fortran code")
 +    def test_svd_fixed_precision(self, A, L, eps, rand, lin_op, rng):
          A_or_L = A if not lin_op else L
-
+ 
 -        U, S, V = pymatrixid.svd(A_or_L, eps, rand=rand)
 +        U, S, V = pymatrixid.svd(A_or_L, eps, rand=rand, rng=rng)
          B = U * S @ V.T.conj()
          assert_allclose(A, B, rtol=eps, atol=1e-08)
-
+ 
      @pytest.mark.parametrize(
          "rand,lin_op",
          [(False, False), (True, False), (True, True)])
@@ -21779,23 +21779,23 @@ index ddc56f7c7..95b83dfad 100644
 +    def test_svd_fixed_rank(self, A, L, eps, rank, rand, lin_op, rng):
          k = rank
          A_or_L = A if not lin_op else L
-
+ 
 -        U, S, V = pymatrixid.svd(A_or_L, k, rand=rand)
 +        U, S, V = pymatrixid.svd(A_or_L, k, rand=rand, rng=rng)
          B = U * S @ V.T.conj()
          assert_allclose(A, B, rtol=eps, atol=1e-08)
-
+ 
 @@ -141,59 +137,39 @@ class TestInterpolativeDecomposition:
          B = U * S @ V.T.conj()
          assert_allclose(A, B, rtol=eps, atol=1e-08)
-
+ 
 -    def test_estimate_spectral_norm(self, A):
 +    def test_estimate_spectral_norm(self, A, rng):
          s = svdvals(A)
 -        norm_2_est = pymatrixid.estimate_spectral_norm(A)
 +        norm_2_est = pymatrixid.estimate_spectral_norm(A, rng=rng)
          assert_allclose(norm_2_est, s[0], rtol=1e-6, atol=1e-8)
-
+ 
 -    def test_estimate_spectral_norm_diff(self, A):
 +    def test_estimate_spectral_norm_diff(self, A, rng):
          B = A.copy()
@@ -21804,11 +21804,11 @@ index ddc56f7c7..95b83dfad 100644
 -        norm_2_est = pymatrixid.estimate_spectral_norm_diff(A, B)
 +        norm_2_est = pymatrixid.estimate_spectral_norm_diff(A, B, rng=rng)
          assert_allclose(norm_2_est, s[0], rtol=1e-6, atol=1e-8)
-
+ 
 -    def test_rank_estimates_array(self, A):
 +    def test_rank_estimates_array(self, A, rng):
          B = np.array([[1, 1, 0], [0, 0, 1], [0, 0, 1]], dtype=A.dtype)
-
+ 
          for M in [A, B]:
              rank_tol = 1e-9
              rank_np = np.linalg.matrix_rank(M, norm(M, 2) * rank_tol)
@@ -21816,11 +21816,11 @@ index ddc56f7c7..95b83dfad 100644
 +            rank_est = pymatrixid.estimate_rank(M, rank_tol, rng=rng)
              assert_(rank_est >= rank_np)
              assert_(rank_est <= rank_np + 10)
-
+ 
 -    def test_rank_estimates_lin_op(self, A):
 +    def test_rank_estimates_lin_op(self, A, rng):
          B = np.array([[1, 1, 0], [0, 0, 1], [0, 0, 1]], dtype=A.dtype)
-
+ 
          for M in [A, B]:
              ML = aslinearoperator(M)
              rank_tol = 1e-9
@@ -21829,7 +21829,7 @@ index ddc56f7c7..95b83dfad 100644
 +            rank_est = pymatrixid.estimate_rank(ML, rank_tol, rng=rng)
              assert_(rank_est >= rank_np - 4)
              assert_(rank_est <= rank_np + 4)
-
+ 
 -    def test_rand(self):
 -        pymatrixid.seed('default')
 -        assert_allclose(pymatrixid.rand(2), [0.8932059, 0.64500803],
@@ -21862,5 +21862,6 @@ index ddc56f7c7..95b83dfad 100644
          A = np.array([[-1, -1, -1, 0, 0, 0],
                        [0, 0, 0, 1, 1, 1],
                        [1, 0, 0, 1, 0, 0],
---
+-- 
 2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch b/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
index e84bf4d1..705d648d 100644
--- a/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
+++ b/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
@@ -15,23 +15,24 @@ index 41afa7e74..5065a15ff 100644
  *          Pullman, WA 99164-3113
  *          Email : alangenz@wsu.edu
  *
--      SUBROUTINE mvnun(d, n, lower, upper, means, covar, maxpts,
+-      SUBROUTINE mvnun(d, n, lower, upper, means, covar, maxpts, 
 -     &                   abseps, releps, value, inform)
-+      RECURSIVE SUBROUTINE mvnun(d, n, lower, upper, means, covar,
++      RECURSIVE SUBROUTINE mvnun(d, n, lower, upper, means, covar, 
 +     &                   maxpts, abseps, releps, value, inform)
  *  Parameters
  *
  *   d       integer, dimensionality of the data
 @@ -88,8 +88,8 @@
-       END
-
-
+       END 
+ 
+ 
 -      SUBROUTINE mvnun_weighted(d, n, lower, upper, means, weights,
--     &                          covar, maxpts, abseps, releps,
-+      recursive SUBROUTINE mvnun_weighted(d, n, lower, upper, means,
+-     &                          covar, maxpts, abseps, releps, 
++      recursive SUBROUTINE mvnun_weighted(d, n, lower, upper, means, 
 +     &                          weights, covar, maxpts, abseps, releps,
       &                           value, inform)
  *  Parameters
  *
---
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch b/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
index 59f8c897..0ca5929f 100644
--- a/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
+++ b/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
@@ -17,7 +17,7 @@ index ca74f7a..c447a6a 100644
 @@ -2,8 +2,8 @@ c
  c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
  c
-
+ 
 -      subroutine zreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
 -     c     iflag)
 +      recursive subroutine zreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
@@ -28,10 +28,10 @@ index ca74f7a..c447a6a 100644
 @@ -103,7 +103,7 @@ c
  c****************************************************************************
  c
-
+ 
 -      subroutine zcgs(n,k,V,ldv,vnew,index,work)
 +      recursive subroutine zcgs(n,k,V,ldv,vnew,index,work)
-
+ 
  c     Block  Gram-Schmidt orthogonalization:
  c     FOR i= 1:l
 diff --git a/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F b/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F
@@ -41,7 +41,7 @@ index cd87247..e657a89 100644
 @@ -2,8 +2,8 @@ c
  c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
  c
-
+ 
 -      subroutine creorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
 -     c     iflag)
 +      recursive subroutine creorth(n,k,V,ldv,vnew,normvnew,index,alpha,
@@ -52,10 +52,10 @@ index cd87247..e657a89 100644
 @@ -103,7 +103,7 @@ c
  c****************************************************************************
  c
-
+ 
 -      subroutine ccgs(n,k,V,ldv,vnew,index,work)
 +      recursive subroutine ccgs(n,k,V,ldv,vnew,index,work)
-
+ 
  c     Block  Gram-Schmidt orthogonalization:
  c     FOR i= 1:l
 diff --git a/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F b/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F
@@ -65,7 +65,7 @@ index 841208a..fec923e 100644
 @@ -2,8 +2,8 @@ c
  c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
  c
-
+ 
 -      subroutine dreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
 -     c     iflag)
 +      recursive subroutine dreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
@@ -76,10 +76,10 @@ index 841208a..fec923e 100644
 @@ -103,7 +103,7 @@ c
  c****************************************************************************
  c
-
+ 
 -      subroutine dcgs(n,k,V,ldv,vnew,index,work)
 +      recursive subroutine dcgs(n,k,V,ldv,vnew,index,work)
-
+ 
  c     Block  Gram-Schmidt orthogonalization:
  c     FOR i= 1:l
 diff --git a/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F b/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F
@@ -89,7 +89,7 @@ index 644d404..61b6698 100644
 @@ -2,8 +2,8 @@ c
  c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
  c
-
+ 
 -      subroutine sreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
 -     c     iflag)
 +      recursive subroutine sreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
@@ -100,11 +100,12 @@ index 644d404..61b6698 100644
 @@ -103,7 +103,7 @@ c
  c****************************************************************************
  c
-
+ 
 -      subroutine scgs(n,k,V,ldv,vnew,index,work)
 +      recursive subroutine scgs(n,k,V,ldv,vnew,index,work)
-
+ 
  c     Block  Gram-Schmidt orthogonalization:
  c     FOR i= 1:l
---
+-- 
 2.34.1
+
diff --git a/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch b/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
index f30a8499..ad975ccd 100644
--- a/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
+++ b/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
@@ -72,5 +72,5 @@ index bb43e3b2e9..358279a93b 100644
    link_args: version_link_args,
    install: true,
    link_language: 'fortran',
---
+-- 
 2.39.3 (Apple Git-146)
diff --git a/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch b/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
index f9e1538d..78272f58 100644
--- a/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
+++ b/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
@@ -89,5 +89,6 @@ index 75a58c40ec..215f38f31f 100644
    60  continue
    70  ier = 0
    80  return
---
+-- 
 2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch b/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch
index 1edf5e07..c4afc190 100644
--- a/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch
+++ b/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch
@@ -22,5 +22,6 @@ index 1f3dc226ab..28aa8b8c22 100644
  void chpcon(char *uplo, int *n, c *ap, int *ipiv, s *anorm, s *rcond, c *work, int *info)
  void chpev(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, s *rwork, int *info)
  void chpevd(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, int *lwork, s *rwork, int *lrwork, int *iwork, int *liwork, int *info)
---
+-- 
 2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch b/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch
index 7c9e357f..c20be03f 100644
--- a/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch
+++ b/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch
@@ -20,5 +20,6 @@ index 8a00f5d279..aeb86e8926 100644
      blas_macro, blas_name = get_blas_macro_and_name(name, accelerate)
      c_args = ', '.join(f'{t} *{n}' for t, n in zip(c_argtypes, argnames))
      return f"{c_return_type} {blas_macro}({blas_name})({c_args});\n"
---
+-- 
 2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch b/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
index 537c4f6d..b9e521f3 100644
--- a/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
+++ b/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
@@ -24,27 +24,28 @@ index b43016c027..cbd80252b1 100644
  import itertools
  import platform
 +import sys
-
+ 
  import numpy as np
  from numpy.testing import (assert_equal, assert_almost_equal,
 @@ -37,6 +38,8 @@ try:
  except ImportError:
      CONFIG = None
-
+ 
 +IS_WASM = (sys.platform == "emscripten" or platform.machine() in ["wasm32", "wasm64"])
 +
-
+ 
  def _random_hermitian_matrix(n, posdef=False, dtype=float):
      "Generate random sym/hermitian array of the given size n"
 @@ -1179,6 +1182,9 @@ class TestSVD_GESVD(TestSVD_GESDD):
      lapack_driver = 'gesvd'
-
-
+ 
+ 
 +# Allocating an array of such a size leads to _ArrayMemoryError(s)
 +# since the maximum memory that can be in 32-bit (WASM) is 4GB
 +@pytest.mark.skipif(IS_WASM, reason="out of memory in WASM")
  @pytest.mark.fail_slow(5)
  def test_svd_gesdd_nofegfault():
      # svd(a) with {U,VT}.size > INT_MAX does not segfault
---
+-- 
 2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch b/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
index 6e17b59a..a80ca320 100644
--- a/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
+++ b/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
@@ -33,7 +33,7 @@ index cfaa927139..44c63fa526 100644
 @@ -128,8 +128,14 @@ py3.extension_module('_odepack',
    subdir: 'scipy/integrate'
  )
-
+ 
 +vode_module = custom_target('vode_module',
 +  output: ['_vode-f2pywrappers.f', '_vodemodule.c'],
 +  input: 'vode.pyf',
@@ -49,7 +49,7 @@ index cfaa927139..44c63fa526 100644
 @@ -139,8 +145,14 @@ py3.extension_module('_vode',
    subdir: 'scipy/integrate'
  )
-
+ 
 +lsoda_module = custom_target('lsoda_module',
 +  output: ['_lsoda-f2pywrappers.f', '_lsodamodule.c'],
 +  input: 'lsoda.pyf',
@@ -65,7 +65,7 @@ index cfaa927139..44c63fa526 100644
 @@ -150,8 +162,14 @@ py3.extension_module('_lsoda',
    subdir: 'scipy/integrate'
  )
-
+ 
 +_dop_module = custom_target('_dop_module',
 +  output: ['_dop-f2pywrappers.f', '_dopmodule.c'],
 +  input: 'dop.pyf',
@@ -81,7 +81,7 @@ index cfaa927139..44c63fa526 100644
 @@ -169,8 +187,14 @@ py3.extension_module('_test_multivariate',
    install_tag: 'tests'
  )
-
+ 
 +_test_odeint_banded_module = custom_target('_test_odeint_banded_module',
 +  output: ['_test_odeint_bandedmodule.c', '_test_odeint_banded-f2pywrappers.f'],
 +  input: 'tests/test_odeint_banded.pyf',
@@ -101,7 +101,7 @@ index 69ec25f6af..38dd2a8cc3 100644
 @@ -143,9 +143,15 @@ py3.extension_module('_fitpack',
    subdir: 'scipy/interpolate'
  )
-
+ 
 +dfitpack_module = custom_target('dfitpack_module',
 +  output: ['_dfitpack-f2pywrappers.f', '_dfitpackmodule.c'],
 +  input: 'src/dfitpack.pyf',
@@ -140,7 +140,7 @@ index a0857848a2..ff47bde52e 100644
 @@ -144,30 +144,6 @@ fortranobject_dep = declare_dependency(
    compile_args: _f2py_c_args,
  )
-
+ 
 -f2py = find_program('f2py')
 -# It should be quite rare for the `f2py` executable to not be the one from
 -# `numpy` installed in the Python env we are building for (unless we are
@@ -175,7 +175,7 @@ index 50d62ef68b..6cef85027a 100644
 @@ -92,12 +92,18 @@ py3.extension_module('_zeros',
    subdir: 'scipy/optimize'
  )
-
+ 
 +lbfgsb_module = custom_target('lbfgsb_module',
 +  output: ['_lbfgsb-f2pywrappers.f', '_lbfgsbmodule.c'],
 +  input: 'lbfgsb_src/lbfgsb.pyf',
@@ -195,7 +195,7 @@ index 50d62ef68b..6cef85027a 100644
 @@ -120,6 +126,12 @@ py3.extension_module('_moduleTNC',
    subdir: 'scipy/optimize'
  )
-
+ 
 +cobyla_module = custom_target('cobyla_module',
 +  output: ['_cobylamodule.c'],
 +  input: 'cobyla/cobyla.pyf',
@@ -209,7 +209,7 @@ index 50d62ef68b..6cef85027a 100644
 @@ -131,8 +143,14 @@ py3.extension_module('_cobyla',
    subdir: 'scipy/optimize'
  )
-
+ 
 +minpack2_module = custom_target('minpack2_module',
 +  output: ['_minpack2module.c'],
 +  input: 'minpack2/minpack2.pyf',
@@ -225,7 +225,7 @@ index 50d62ef68b..6cef85027a 100644
 @@ -142,8 +160,14 @@ py3.extension_module('_minpack2',
    subdir: 'scipy/optimize'
  )
-
+ 
 +slsqp_module = custom_target('slsqp_module',
 +  output: ['_slsqpmodule.c'],
 +  input: 'slsqp/slsqp.pyf',
@@ -245,7 +245,7 @@ index 6714724958..df358df651 100644
 @@ -97,8 +97,14 @@ foreach ele: elements
      gnu_symbol_visibility: 'hidden',
    )
-
+ 
 +  propack_module = custom_target('propack_module' + ele[0],
 +    output: [ele[0] + '-f2pywrappers.f', ele[0] + 'module.c'],
 +    input: ele[2],
@@ -265,7 +265,7 @@ index 358279a93b..7c973b1cf3 100644
 @@ -31,8 +31,14 @@ py3.extension_module('_ansari_swilk_statistics',
    subdir: 'scipy/stats'
  )
-
+ 
 +mvn_module = custom_target('mvn_module',
 +  output: ['_mvn-f2pywrappers.f', '_mvnmodule.c'],
 +  input: 'mvn.pyf',
@@ -287,11 +287,11 @@ index b6bc02eb04..3da75c14d1 100644
  import re
  import subprocess
 +import sys
-
-
+ 
+ 
  # START OF CODE VENDORED FROM `numpy.distutils.from_template`
 @@ -283,7 +284,7 @@ def main():
-
+ 
      # Now invoke f2py to generate the C API module file
      if args.infile.endswith(('.pyf.src', '.pyf')):
 -        p = subprocess.Popen(['f2py', fname_pyf,
@@ -299,5 +299,6 @@ index b6bc02eb04..3da75c14d1 100644
                              '--build-dir', outdir_abs], #'--quiet'],
                              stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                              cwd=os.getcwd())
---
+-- 
 2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch b/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
index f01ce6fc..9f45ad86 100644
--- a/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
+++ b/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
@@ -17,11 +17,12 @@ index 82b813ea85..24bee0a21c 100644
 @@ -33,7 +33,7 @@ else
    scipy_import_dll_args = []
  endif
-
+ 
 -sf_error_state_lib = shared_library('sf_error_state',
 +sf_error_state_lib = static_library('sf_error_state',
    ['sf_error_state.c'],
    include_directories: ['../_lib', '../_build_utils/src'],
    c_args: scipy_export_dll_args,
---
+-- 
 2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch b/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
index 12e3cbf1..56be63ec 100644
--- a/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
+++ b/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
@@ -18,7 +18,7 @@ index ae9e2466e1..e11626db0d 100644
 @@ -187,24 +187,6 @@ py3.extension_module('_test_multivariate',
    install_tag: 'tests'
  )
-
+ 
 -_test_odeint_banded_module = custom_target('_test_odeint_banded_module',
 -  output: ['_test_odeint_bandedmodule.c', '_test_odeint_banded-f2pywrappers.f'],
 -  input: 'tests/test_odeint_banded.pyf',
@@ -39,7 +39,7 @@ index ae9e2466e1..e11626db0d 100644
 -
  subdir('_ivp')
  subdir('tests')
-
+ 
 diff --git a/scipy/io/meson.build b/scipy/io/meson.build
 index d6fc6dc749..af04022208 100644
 --- a/scipy/io/meson.build
@@ -69,5 +69,6 @@ index d6fc6dc749..af04022208 100644
  py3.install_sources([
      '__init__.py',
      '_fortran.py',
---
+-- 
 2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch b/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
index f090254c..e2ffa67b 100644
--- a/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
+++ b/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
@@ -20,7 +20,7 @@ index 99d4886558..bf7256e605 100644
 @@ -2310,13 +2310,12 @@ function lange(norm,m,n,a,lda,work) result(n2)
       dimension(m+1),intent(cache,hide) :: work
  end function lange
-
+ 
 -subroutine larfg(n, alpha, x, incx, tau, lx)
 +subroutine larfg(n, alpha, x, incx, tau)
      integer intent(in), check(n>=1) :: n
@@ -31,7 +31,8 @@ index 99d4886558..bf7256e605 100644
       intent(out) :: tau
 -    integer intent(hide),depend(x,n,incx),check(lx > (n-2)*incx) :: lx = len(x)
  end subroutine larfg
-
+ 
  subroutine larf(side,m,n,v,incv,tau,c,ldc,work,lwork)
---
+-- 
 2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/test_scipy.py b/integration_tests/recipes/scipy/test_scipy.py
index 658eb87f..ebd09bed 100644
--- a/integration_tests/recipes/scipy/test_scipy.py
+++ b/integration_tests/recipes/scipy/test_scipy.py
@@ -47,9 +47,10 @@ def test_binom_ppf(selenium):
 @pytest.mark.driver_timeout(40)
 @run_in_pyodide(packages=["pytest", "scipy-tests", "micropip"])
 async def test_scipy_pytest(selenium):
-    import micropip
     import pytest
 
+    import micropip
+
     await micropip.install("hypothesis")
 
     def runtest(module, filter):

From 2f5bc3b913dd1645af24676154be2ec39d232e2d Mon Sep 17 00:00:00 2001
From: Gyeongjae Choi 
Date: Wed, 16 Oct 2024 11:21:51 +0000
Subject: [PATCH 16/71] Remove uncessery arg

---
 .pre-commit-config.yaml | 2 --
 1 file changed, 2 deletions(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 246e3b58..fafd897c 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -44,8 +44,6 @@ repos:
           [
             "--ignore-words-list",
             "ags,aray,asend,ba,classs,crate,falsy,feld,inflight,lits,nd,slowy,te,oint,conveniant",
-            "--skip",
-            "*.patch",
           ]
 
   - repo: https://github.com/pre-commit/mirrors-mypy

From 0feb9aac4187a1d701901a151d5542118cf62e76 Mon Sep 17 00:00:00 2001
From: Gyeongjae Choi 
Date: Wed, 16 Oct 2024 12:11:42 +0000
Subject: [PATCH 17/71] Force install cross-build package even if version
 mismatches [integration]

---
 pyodide_build/pypabuild.py            |  9 ++++++++-
 pyodide_build/tests/test_pypabuild.py | 20 ++++++++++++++++++--
 2 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index b813a508..34776e26 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -157,7 +157,14 @@ def _replace_unisolated_packages(
     for reqstr in list(requires):
         req = Requirement(reqstr)
         for name, version in unisolated_packages.items():
-            if req.name == name and req.specifier.contains(version):
+            if req.name == name:
+                # TODO: find a better way to handle this case
+                if not req.specifier.contains(version):
+                    print(
+                        f"WARNING: found build dependency {req} but the only supported cross-build version is {name}=={version}"
+                    )
+                    print(f"WARNING: using {name}=={version} instead")
+
                 requires_new.remove(reqstr)
                 requires_new.add(f"{name}=={version}")
                 unisolated.add(name)
diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py
index ffd677e3..7b53835f 100644
--- a/pyodide_build/tests/test_pypabuild.py
+++ b/pyodide_build/tests/test_pypabuild.py
@@ -103,14 +103,30 @@ def test_replace_unisolated_packages():
     unisolated = {
         "foo": "2.0",
         "bar": "0.5",
-        "baz": "1.1",
+        "baz": "1.0",
     }
 
     new_requires, replaced = pypabuild._replace_unisolated_packages(
         requires, unisolated
     )
     assert new_requires == {"foo==2.0", "bar==0.5", "baz==1.0", "qux"}
-    assert replaced == {"foo", "bar"}
+    assert replaced == {"foo", "bar", "baz"}
+
+
+def test_replace_unisolated_packages_version_mismatch():
+    """
+    FIXME: This is not an ideal behavior, but for now wejust ignore the version mismatch.
+    """
+    requires = {"baz==1.0"}
+    unisolated = {
+        "baz": "1.1",
+    }
+
+    new_requires, replaced = pypabuild._replace_unisolated_packages(
+        requires, unisolated
+    )
+    assert new_requires == {"baz==1.1"}
+    assert replaced == {"baz"}
 
 
 def test_replace_unisoloated_packages_oldest_supported_numpy():

From f72ca2aa06e7275f6515cd1110d81c47a86ae13c Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 14:56:32 +0530
Subject: [PATCH 18/71] Update SciPy integration test to 1.17.1, drop f2py
 generators patch

---
 integration_tests/recipes/scipy/meta.yaml     |    74 +-
 ...-Fix-dstevr-in-special-lapack_defs.h.patch |     2 +-
 ...-const.patch => 0002-gemm_-no-const.patch} |     2 +-
 .../scipy/patches/0002-int-to-string.patch    |    29 -
 ...atch => 0003-make-int-return-values.patch} |   106 +-
 ...x-fitpack.patch => 0004-Fix-fitpack.patch} |     2 +-
 ...-calls.patch => 0005-Fix-gees-calls.patch} |     2 +-
 ...enblas-with-modules-that-require-f2c.patch |    30 +
 ...-linalg-Remove-id_dist-Fortran-files.patch | 21867 ----------------
 ...patch => 0007-Remove-chla_transtype.patch} |    54 +-
 ...0008-Mark-mvndst-functions-recursive.patch |    38 -
 ...0008-Set-wrapper-return-type-to-int.patch} |     2 +-
 .../patches/0009-Make-sreorth-recursive.patch |   111 -
 ...nvert-return-value-of-SUPERLU_MALLOC.patch |    76 +
 ...enblas-with-modules-that-require-f2c.patch |    76 -
 ...ove-dummy-argument-from-larf-wrapper.patch |    46 +
 ...chec-inline-if-then-endif-constructs.patch |    94 -
 .../patches/0014-Skip-svd_gesdd-test.patch    |    51 -
 .../patches/0015-Remove-f2py-generators.patch |   304 -
 ...-sf_error_state_lib-a-static-library.patch |    28 -
 ...move-test-modules-that-fail-to-build.patch |    74 -
 ...-Fix-lapack-larfg-function-signature.patch |    38 -
 .../recipes/scipy/scipy-conftest.py           |    99 +-
 .../recipes/scipy/scipy-pytest.js             |    84 -
 integration_tests/recipes/scipy/test_scipy.py |    16 +-
 25 files changed, 343 insertions(+), 22962 deletions(-)
 rename integration_tests/recipes/scipy/patches/{0003-gemm_-no-const.patch => 0002-gemm_-no-const.patch} (99%)
 delete mode 100644 integration_tests/recipes/scipy/patches/0002-int-to-string.patch
 rename integration_tests/recipes/scipy/patches/{0004-make-int-return-values.patch => 0003-make-int-return-values.patch} (68%)
 rename integration_tests/recipes/scipy/patches/{0005-Fix-fitpack.patch => 0004-Fix-fitpack.patch} (99%)
 rename integration_tests/recipes/scipy/patches/{0006-Fix-gees-calls.patch => 0005-Fix-gees-calls.patch} (98%)
 create mode 100644 integration_tests/recipes/scipy/patches/0006-Link-openblas-with-modules-that-require-f2c.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
 rename integration_tests/recipes/scipy/patches/{0012-Remove-chla_transtype.patch => 0007-Remove-chla_transtype.patch} (89%)
 delete mode 100644 integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
 rename integration_tests/recipes/scipy/patches/{0013-Set-wrapper-return-type-to-int.patch => 0008-Set-wrapper-return-type-to-int.patch} (94%)
 delete mode 100644 integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
 create mode 100644 integration_tests/recipes/scipy/patches/0010-Explicitly-convert-return-value-of-SUPERLU_MALLOC.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
 create mode 100644 integration_tests/recipes/scipy/patches/0011-MAINT-linalg-Remove-dummy-argument-from-larf-wrapper.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
 delete mode 100644 integration_tests/recipes/scipy/scipy-pytest.js

diff --git a/integration_tests/recipes/scipy/meta.yaml b/integration_tests/recipes/scipy/meta.yaml
index 959954fa..6bff24da 100644
--- a/integration_tests/recipes/scipy/meta.yaml
+++ b/integration_tests/recipes/scipy/meta.yaml
@@ -1,8 +1,9 @@
 package:
   name: scipy
-  version: 1.14.1
+  version: 1.17.1
   tag:
     - min-scipy-stack
+    - cross-build
   top-level:
     - scipy
 
@@ -17,44 +18,45 @@ package:
 # subroutine. Try deleting it.
 
 source:
-  url: https://files.pythonhosted.org/packages/62/11/4d44a1f274e002784e4dbdb81e0ea96d2de2d1045b2132d5af62cc31fd28/scipy-1.14.1.tar.gz
-  sha256: 5a275584e726026a5699459aa72f828a610821006228e841b94275c4a7c08417
+  url: https://files.pythonhosted.org/packages/source/s/scipy/scipy-1.17.1.tar.gz
+  sha256: 95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0
 
   patches:
     - patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
-    - patches/0002-int-to-string.patch
-    - patches/0003-gemm_-no-const.patch
-    - patches/0004-make-int-return-values.patch
-    - patches/0005-Fix-fitpack.patch
-    - patches/0006-Fix-gees-calls.patch
-    - patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
-    - patches/0008-Mark-mvndst-functions-recursive.patch
-    - patches/0009-Make-sreorth-recursive.patch
-    - patches/0010-Link-openblas-with-modules-that-require-f2c.patch
-    - patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch # remove with SciPy v1.15.0
-    - patches/0012-Remove-chla_transtype.patch
-    - patches/0013-Set-wrapper-return-type-to-int.patch
-    - patches/0014-Skip-svd_gesdd-test.patch # remove with SciPy v1.15.0
-    - patches/0015-Remove-f2py-generators.patch
-    - patches/0016-Make-sf_error_state_lib-a-static-library.patch
-    - patches/0017-Remove-test-modules-that-fail-to-build.patch
-    - patches/0018-Fix-lapack-larfg-function-signature.patch
-
+    - patches/0002-gemm_-no-const.patch
+    - patches/0003-make-int-return-values.patch
+    - patches/0004-Fix-fitpack.patch
+    - patches/0005-Fix-gees-calls.patch
+    - patches/0006-Link-openblas-with-modules-that-require-f2c.patch
+    - patches/0007-Remove-chla_transtype.patch
+    - patches/0008-Set-wrapper-return-type-to-int.patch
+    - patches/0010-Explicitly-convert-return-value-of-SUPERLU_MALLOC.patch
+    - patches/0011-MAINT-linalg-Remove-dummy-argument-from-larf-wrapper.patch # drop after scipy 1.18
 build:
+  vendor-sharedlib: true
+  # NumPy 2.1 disabled visibility for symbols outside of extension modules
+  # by default, so this breaks SciPy tests from modules that use f2py to
+  # build because they rely on the visibility of symbols in NumPy. This flag
+  # is currently used as a stop-gap measure. For more information, please see
+  # 1. https://github.com/numpy/numpy/pull/26286, and
+  # 2. https://github.com/numpy/numpy/pull/26103.
   cflags: |
+    -DNPY_API_SYMBOL_ATTRIBUTE=__attribute__((visibility("default")))
     -I$(WASM_LIBRARY_DIR)/include
     -Wno-return-type
     -DUNDERSCORE_G77
     -fvisibility=default
   cxxflags: |
-    -fexceptions
+    -fwasm-exceptions
     -fvisibility=default
   ldflags: |
     -L$(NUMPY_LIB)/core/lib/
     -L$(NUMPY_LIB)/random/lib/
-    -fexceptions
+    -fwasm-exceptions
 
   # Exclude tests via Meson's install tags functionality.
+  # unvendor-tests is automatically set to false by the CI SciPy trigger, so
+  # that when we want to test SciPy, we retain the tests inside the wheel
   unvendor-tests: true
   # install-args=--tags=runtime,python-runtime,devel
   # Disable when running tests, enable when a PR is ready, i.e., building for distribution.
@@ -90,7 +92,21 @@ build:
     sed -i 's/extern void/extern int/g' scipy/optimize/__minpack.h
     sed -i 's/void/int/g' scipy/linalg/cython_blas_signatures.txt
     sed -i 's/void/int/g' scipy/linalg/cython_lapack_signatures.txt
+    sed -i 's/^void BLAS_FUNC/int BLAS_FUNC/g' scipy/linalg/src/_common_array_utils.hh
+
+    # Change fortran functions called in C code to return int instead of void
+    # This adhoc regex checks function names ending with _ such as `void zgetrs_(`
+    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/linalg/_common_array_utils.h
+    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/linalg/_matfuncs_expm.h
+    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/sparse/linalg/_propack/PROPACK/src/include/blaslapack_declarations.h
+    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/sparse/linalg/_eigen/arpack/arnaud/src/blaslapack_declarations.h
+    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/integrate/src/blaslapack_declarations.h
+    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/optimize/__lbfgsb.h
+    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/optimize/__nnls.h
+    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/optimize/__slsqp.h
+
     sed -i 's/^void/int/g' scipy/interpolate/src/_fitpackmodule.c
+    sed -i 's/void BLAS_FUNC/int BLAS_FUNC/g' scipy/interpolate/src/__fitpack.h
 
     sed -i 's/extern void/extern int/g' scipy/sparse/linalg/_dsolve/SuperLU/SRC/*.{c,h}
     sed -i 's/PUBLIC void/PUBLIC int/g' scipy/sparse/linalg/_dsolve/SuperLU/SRC/*.{c,h}
@@ -112,6 +128,10 @@ build:
     # Input error causes "duplicate symbol" linker errors. Empty out the file.
     echo "" > scipy/sparse/linalg/_dsolve/SuperLU/SRC/input_error.c
 
+    # https://github.com/mesonbuild/meson/blob/e542901af6e30865715d3c3c18f703910a096ec0/mesonbuild/backend/ninjabackend.py#L94
+    # Prevent from using response file. The response file that meson generates is not compatible to pyodide-build
+    export MESON_RSP_THRESHOLD=131072
+
   _retain-test-patterns:
     - "*_page_trend_test.py"
     - "*bws_test.py"
@@ -124,13 +144,15 @@ build:
 requirements:
   host:
     - numpy
-    - openblas
+    - libopenblas
+    - libboost
   run:
     - numpy
-    - openblas
   executable:
     - gfortran
-
+  constraint:
+    # Getting: Error: Dynamic linking error: cannot resolve symbol pow_di
+    - meson < 1.10
 test:
   imports:
     - scipy
diff --git a/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch b/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
index ca6d80a0..c046c534 100644
--- a/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
+++ b/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
@@ -1,7 +1,7 @@
 From 45a31145679c83f2719b6420f234d484b9459697 Mon Sep 17 00:00:00 2001
 From: Hood Chatham 
 Date: Fri, 18 Mar 2022 16:25:39 -0700
-Subject: [PATCH 1/18] Fix dstevr in special/lapack_defs.h
+Subject: [PATCH 01/11] Fix dstevr in special/lapack_defs.h
 
 ---
  scipy/special/lapack_defs.h | 5 ++---
diff --git a/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch b/integration_tests/recipes/scipy/patches/0002-gemm_-no-const.patch
similarity index 99%
rename from integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch
rename to integration_tests/recipes/scipy/patches/0002-gemm_-no-const.patch
index 3840f745..e8e1db46 100644
--- a/integration_tests/recipes/scipy/patches/0003-gemm_-no-const.patch
+++ b/integration_tests/recipes/scipy/patches/0002-gemm_-no-const.patch
@@ -1,7 +1,7 @@
 From e528227dd37c8b0512381992c222789a114e3169 Mon Sep 17 00:00:00 2001
 From: Hood Chatham 
 Date: Sat, 18 Dec 2021 11:41:15 -0800
-Subject: [PATCH 3/18] gemm_ no const
+Subject: [PATCH 02/11] gemm_ no const
 
 cgemm, dgemm, sgemm, and zgemm are declared with `const` in slu_cdefs.h, but
 other places don't have the cosnt causing compile errors.
diff --git a/integration_tests/recipes/scipy/patches/0002-int-to-string.patch b/integration_tests/recipes/scipy/patches/0002-int-to-string.patch
deleted file mode 100644
index 7a172cb2..00000000
--- a/integration_tests/recipes/scipy/patches/0002-int-to-string.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From d53ade3f03ba3557fd50fb38990d605f4ae7f8f1 Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Sat, 25 Dec 2021 18:04:18 -0800
-Subject: [PATCH 2/18] int to string
-
-f2c does not handle implicit casts of function arguments correctly. The msg
-argument of `xerrwv` is defined to be an `int *`, and then implicitly cast
-from a string at the call site. This doesn't work correctly.
-
-We redefine the type of the first argument to be string to fix the problem.
----
- scipy/integrate/odepack/xerrwv.f | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/scipy/integrate/odepack/xerrwv.f b/scipy/integrate/odepack/xerrwv.f
-index 7e180e4f8..b940bb702 100644
---- a/scipy/integrate/odepack/xerrwv.f
-+++ b/scipy/integrate/odepack/xerrwv.f
-@@ -1,5 +1,6 @@
-       subroutine xerrwv (msg, nmes, nerr, level, ni, i1, i2, nr, r1, r2)
--      integer msg, nmes, nerr, level, ni, i1, i2, nr,
-+      character  msg*1
-+      integer nmes, nerr, level, ni, i1, i2, nr,
-      1   i, lun, lunit, mesflg, ncpw, nch, nwds
-       double precision r1, r2
-       dimension msg(nmes)
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch b/integration_tests/recipes/scipy/patches/0003-make-int-return-values.patch
similarity index 68%
rename from integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch
rename to integration_tests/recipes/scipy/patches/0003-make-int-return-values.patch
index 5abeb4f0..65b0d089 100644
--- a/integration_tests/recipes/scipy/patches/0004-make-int-return-values.patch
+++ b/integration_tests/recipes/scipy/patches/0003-make-int-return-values.patch
@@ -1,7 +1,7 @@
 From a86a2304fd925f815bbb0e0753e46a7b863e2de2 Mon Sep 17 00:00:00 2001
 From: Joe Marshall 
 Date: Wed, 6 Apr 2022 21:25:13 -0700
-Subject: [PATCH 4/18] make int return values
+Subject: [PATCH 03/11] make int return values
 
 The return values of f2c functions are insignificant in most cases, so often it
 is treated as returning void, when it really should return int (values are
@@ -98,40 +98,6 @@ index f35c94f984..1872d335aa 100644
      *ret = F_FUNC(wzladiv,WZLADIV)(x, y);
  }
  
-diff --git a/scipy/integrate/_odepackmodule.c b/scipy/integrate/_odepackmodule.c
-index 0c8067e652..d085939859 100644
---- a/scipy/integrate/_odepackmodule.c
-+++ b/scipy/integrate/_odepackmodule.c
-@@ -156,17 +156,17 @@ static PyObject *odepack_error;
-     #endif
- #endif
- 
--typedef void lsoda_f_t(F_INT *n, double *t, double *y, double *ydot);
-+typedef int lsoda_f_t(F_INT *n, double *t, double *y, double *ydot);
- typedef int lsoda_jac_t(F_INT *n, double *t, double *y, F_INT *ml, F_INT *mu,
-                         double *pd, F_INT *nrowpd);
- 
--void LSODA(lsoda_f_t *f, F_INT *neq, double *y, double *t, double *tout, F_INT *itol,
-+int LSODA(lsoda_f_t *f, F_INT *neq, double *y, double *t, double *tout, F_INT *itol,
-            double *rtol, double *atol, F_INT *itask, F_INT *istate, F_INT *iopt,
-            double *rwork, F_INT *lrw, F_INT *iwork, F_INT *liw, lsoda_jac_t *jac,
-            F_INT *jt);
- 
- /*
--void ode_function(int *n, double *t, double *y, double *ydot)
-+int ode_function(int *n, double *t, double *y, double *ydot)
- {
-   ydot[0] = -0.04*y[0] + 1e4*y[1]*y[2];
-   ydot[2] = 3e7*y[1]*y[1];
-@@ -175,7 +175,7 @@ void ode_function(int *n, double *t, double *y, double *ydot)
- }
- */
- 
--void
-+int
- ode_function(F_INT *n, double *t, double *y, double *ydot)
- {
-     /*
 diff --git a/scipy/odr/__odrpack.c b/scipy/odr/__odrpack.c
 index c806e33fbf..c4b822eb92 100644
 --- a/scipy/odr/__odrpack.c
@@ -185,9 +151,9 @@ index 5afc93b5d9..7ac5f80fb9 100644
  
  #include 
  
++#undef complex
 +#include "f2c.h"
-+
-+
++#define complex singlecomplex
  /*
   * Support routines
   */
@@ -274,72 +240,6 @@ index 49b928a431..0822687719 100644
  	     int *g, int h[], int *i, int j[], int *k, double l[],
  	     int m[], int n[])
  {
-diff --git a/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/debug.h b/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/debug.h
-index 5eb0bb1b3d..81a6efafb9 100644
---- a/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/debug.h
-+++ b/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/debug.h
-@@ -1,16 +1,16 @@
--c
-+
- c\SCCS Information: @(#) 
- c FILE: debug.h   SID: 2.3   DATE OF SID: 11/16/95   RELEASE: 2 
- c
- c     %---------------------------------%
- c     | See debug.doc for documentation |
- c     %---------------------------------%
--      integer  logfil, ndigit, mgetv0,
--     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
--     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
--     &         mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd
--      common /debug/ 
--     &         logfil, ndigit, mgetv0,
--     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
--     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
--     &         mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd
-+c      integer  logfil, ndigit, mgetv0,
-+c     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
-+c     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
-+c     &         mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd
-+c      common /debug/
-+c     &         logfil, ndigit, mgetv0,
-+c     &         msaupd, msaup2, msaitr, mseigt, msapps, msgets, mseupd,
-+c     &         mnaupd, mnaup2, mnaitr, mneigh, mnapps, mngets, mneupd,
-+c     &         mcaupd, mcaup2, mcaitr, mceigh, mcapps, mcgets, mceupd
-diff --git a/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h b/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h
-index 66a8e9f87f..81d49c3bd2 100644
---- a/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h
-+++ b/scipy/sparse/linalg/_eigen/arpack/ARPACK/SRC/stat.h
-@@ -5,17 +5,17 @@ c
- c\SCCS Information: @(#) 
- c FILE: stat.h   SID: 2.2   DATE OF SID: 11/16/95   RELEASE: 2 
- c
--      real       t0, t1, t2, t3, t4, t5
--      save       t0, t1, t2, t3, t4, t5
-+c      real       t0, t1, t2, t3, t4, t5
-+c      save       t0, t1, t2, t3, t4, t5
- c
--      integer    nopx, nbx, nrorth, nitref, nrstrt
--      real       tsaupd, tsaup2, tsaitr, tseigt, tsgets, tsapps, tsconv,
--     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
--     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
--     &           tmvopx, tmvbx, tgetv0, titref, trvec
--      common /timing/ 
--     &           nopx, nbx, nrorth, nitref, nrstrt,
--     &           tsaupd, tsaup2, tsaitr, tseigt, tsgets, tsapps, tsconv,
--     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
--     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
--     &           tmvopx, tmvbx, tgetv0, titref, trvec
-+c      integer    nopx, nbx, nrorth, nitref, nrstrt
-+c      real       tsaupd, tsaup2, tsaitr, tseigt, tsgets, tsapps, tsconv,
-+c     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
-+c     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
-+c     &           tmvopx, tmvbx, tgetv0, titref, trvec
-+c      common /timing/
-+c     &           nopx, nbx, nrorth, nitref, nrstrt,
-+c     &           tsaupd, tsaup2, tsaitr, tseigt, tsgets, tsapps, tsconv,
-+c     &           tnaupd, tnaup2, tnaitr, tneigh, tngets, tnapps, tnconv,
-+c     &           tcaupd, tcaup2, tcaitr, tceigh, tcgets, tcapps, tcconv,
-+c     &           tmvopx, tmvbx, tgetv0, titref, trvec
 -- 
 2.34.1
 
diff --git a/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch b/integration_tests/recipes/scipy/patches/0004-Fix-fitpack.patch
similarity index 99%
rename from integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch
rename to integration_tests/recipes/scipy/patches/0004-Fix-fitpack.patch
index 1df3145c..c67bd265 100644
--- a/integration_tests/recipes/scipy/patches/0005-Fix-fitpack.patch
+++ b/integration_tests/recipes/scipy/patches/0004-Fix-fitpack.patch
@@ -1,7 +1,7 @@
 From c784d3a1ee38da88943364de4ea847a3b9cd155f Mon Sep 17 00:00:00 2001
 From: Hood Chatham 
 Date: Tue, 30 Aug 2022 11:51:53 -0700
-Subject: [PATCH 5/18] Fix fitpack
+Subject: [PATCH 04/11] Fix fitpack
 
 ---
  scipy/interpolate/fitpack/dblint.f | 9 ++++-----
diff --git a/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch b/integration_tests/recipes/scipy/patches/0005-Fix-gees-calls.patch
similarity index 98%
rename from integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch
rename to integration_tests/recipes/scipy/patches/0005-Fix-gees-calls.patch
index feabf913..1bf0b0ca 100644
--- a/integration_tests/recipes/scipy/patches/0006-Fix-gees-calls.patch
+++ b/integration_tests/recipes/scipy/patches/0005-Fix-gees-calls.patch
@@ -1,7 +1,7 @@
 From 8addc1da35bc63df651946ef14c723797a431e0c Mon Sep 17 00:00:00 2001
 From: Hood Chatham 
 Date: Mon, 26 Jun 2023 20:12:25 -0700
-Subject: [PATCH 6/18] Fix gees calls
+Subject: [PATCH 05/11] Fix gees calls
 
 ---
  scipy/linalg/flapack_gen.pyf.src | 8 ++++----
diff --git a/integration_tests/recipes/scipy/patches/0006-Link-openblas-with-modules-that-require-f2c.patch b/integration_tests/recipes/scipy/patches/0006-Link-openblas-with-modules-that-require-f2c.patch
new file mode 100644
index 00000000..b8a0fcc3
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0006-Link-openblas-with-modules-that-require-f2c.patch
@@ -0,0 +1,30 @@
+From ccbb0fa0884d567c6139eeed7dc2dc9f8db4db3a Mon Sep 17 00:00:00 2001
+From: ryanking13 
+Date: Sun, 28 Jul 2024 18:15:17 +0900
+Subject: [PATCH 06/11] Link openblas with modules that require f2c
+
+Some fortran modules require symbols from f2c, which is provided by
+openblas.
+This patch adds openblas as a dependency to the modules that require f2c
+symbols.
+
+Co-Developed-by: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
+---
+ scipy/interpolate/meson.build | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/scipy/interpolate/meson.build b/scipy/interpolate/meson.build
+index 33783fc034..877a77539c 100644
+--- a/scipy/interpolate/meson.build
++++ b/scipy/interpolate/meson.build
+@@ -172,7 +172,7 @@ py3.extension_module('_dfitpack',
+   f2py_gen.process('src/dfitpack.pyf', extra_args: extra_f2py_arg),
+   c_args: [Wno_unused_variable] +  c_flags_ilp64,
+   link_args: version_link_args,
+-  dependencies: [fortranobject_dep],
++  dependencies: [lapack, fortranobject_dep],
+   link_with: [fitpack_lib],
+   override_options: ['b_lto=false'],
+   install: true,
+-- 
+2.39.3 (Apple Git-146)
diff --git a/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch b/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
deleted file mode 100644
index e3a57c5b..00000000
--- a/integration_tests/recipes/scipy/patches/0007-MAINT-linalg-Remove-id_dist-Fortran-files.patch
+++ /dev/null
@@ -1,21867 +0,0 @@
-From 12ba8a395ce04194074a24d362143c22e7ac54bd Mon Sep 17 00:00:00 2001
-From: Ilhan Polat 
-Date: Tue, 23 Apr 2024 09:26:38 +0200
-Subject: [PATCH 7/18] MAINT:linalg:Remove id_dist Fortran files
-
-[skip ci]
-
-ENH:linalg:Translate id_dist F77 code to Cython
-
-MAINT:linalg: Convert double to numpy types
-
-MAINT:linalg: Fix linting and a typo in interpolative code
-
-DOC:linalg: Remove non-compliant dash character
-
-MAINT:linalg: Modify meson file for id_dist F77 translation
-
-[skip ci]
-
-MAINT:linalg: Adjust public api for the translated funcs
-
-[skip ci]
-
-ENH:linalg: Modify function signatures for interpolative
-
-[skip ci]
-
-TST:linalg: Adjust tests for the id_dist translation
-
-MAINT:linalg:Remove fortran wrappers for id_dist
-
-[skip ci]
-
-MAINT:linalg:Modify mypy.ini for interpolative Cython code
-
-DOC:linalg: Adjust interpolative docs due to new Cython code
-
-DOC:linalg: Fix grammar and typos
----
- mypy.ini                                      |    2 +-
- scipy/linalg/_decomp_interpolative.pyx        | 1992 +++++++++++
- scipy/linalg/_interpolative_backend.py        | 1681 ---------
- scipy/linalg/interpolative.py                 |  316 +-
- scipy/linalg/meson.build                      |   55 +-
- scipy/linalg/src/id_dist/README.txt           |    6 -
- scipy/linalg/src/id_dist/doc/doc.bib          |   19 -
- scipy/linalg/src/id_dist/doc/doc.tex          |  977 ------
- scipy/linalg/src/id_dist/doc/supertabular.sty |  483 ---
- scipy/linalg/src/id_dist/src/dfft.f           | 3014 -----------------
- scipy/linalg/src/id_dist/src/id_rand.f        |  379 ---
- scipy/linalg/src/id_dist/src/id_rtrans.f      |  746 ----
- scipy/linalg/src/id_dist/src/idd_frm.f        |  525 ---
- scipy/linalg/src/id_dist/src/idd_house.f      |  288 --
- scipy/linalg/src/id_dist/src/idd_id.f         |  560 ---
- scipy/linalg/src/id_dist/src/idd_id2svd.f     |  384 ---
- scipy/linalg/src/id_dist/src/idd_qrpiv.f      |  893 -----
- scipy/linalg/src/id_dist/src/idd_sfft.f       |  443 ---
- scipy/linalg/src/id_dist/src/idd_snorm.f      |  400 ---
- scipy/linalg/src/id_dist/src/idd_svd.f        |  409 ---
- scipy/linalg/src/id_dist/src/iddp_aid.f       |  386 ---
- scipy/linalg/src/id_dist/src/iddp_asvd.f      |  180 -
- scipy/linalg/src/id_dist/src/iddp_rid.f       |  376 --
- scipy/linalg/src/id_dist/src/iddp_rsvd.f      |  216 --
- scipy/linalg/src/id_dist/src/iddr_aid.f       |  208 --
- scipy/linalg/src/id_dist/src/iddr_asvd.f      |  114 -
- scipy/linalg/src/id_dist/src/iddr_rid.f       |  155 -
- scipy/linalg/src/id_dist/src/iddr_rsvd.f      |  157 -
- scipy/linalg/src/id_dist/src/idz_frm.f        |  419 ---
- scipy/linalg/src/id_dist/src/idz_house.f      |  298 --
- scipy/linalg/src/id_dist/src/idz_id.f         |  566 ----
- scipy/linalg/src/id_dist/src/idz_id2svd.f     |  389 ---
- scipy/linalg/src/id_dist/src/idz_qrpiv.f      |  898 -----
- scipy/linalg/src/id_dist/src/idz_sfft.f       |  210 --
- scipy/linalg/src/id_dist/src/idz_snorm.f      |  407 ---
- scipy/linalg/src/id_dist/src/idz_svd.f        |  438 ---
- scipy/linalg/src/id_dist/src/idzp_aid.f       |  390 ---
- scipy/linalg/src/id_dist/src/idzp_asvd.f      |  207 --
- scipy/linalg/src/id_dist/src/idzp_rid.f       |  379 ---
- scipy/linalg/src/id_dist/src/idzp_rsvd.f      |  244 --
- scipy/linalg/src/id_dist/src/idzr_aid.f       |  209 --
- scipy/linalg/src/id_dist/src/idzr_asvd.f      |  118 -
- scipy/linalg/src/id_dist/src/idzr_rid.f       |  156 -
- scipy/linalg/src/id_dist/src/idzr_rsvd.f      |  159 -
- scipy/linalg/src/id_dist/src/prini.f          |  113 -
- scipy/linalg/tests/test_interpolative.py      |   78 +-
- 46 files changed, 2159 insertions(+), 18883 deletions(-)
- create mode 100644 scipy/linalg/_decomp_interpolative.pyx
- delete mode 100644 scipy/linalg/_interpolative_backend.py
- delete mode 100644 scipy/linalg/src/id_dist/README.txt
- delete mode 100644 scipy/linalg/src/id_dist/doc/doc.bib
- delete mode 100644 scipy/linalg/src/id_dist/doc/doc.tex
- delete mode 100644 scipy/linalg/src/id_dist/doc/supertabular.sty
- delete mode 100644 scipy/linalg/src/id_dist/src/dfft.f
- delete mode 100644 scipy/linalg/src/id_dist/src/id_rand.f
- delete mode 100644 scipy/linalg/src/id_dist/src/id_rtrans.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idd_frm.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idd_house.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idd_id.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idd_id2svd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idd_qrpiv.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idd_sfft.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idd_snorm.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idd_svd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/iddp_aid.f
- delete mode 100644 scipy/linalg/src/id_dist/src/iddp_asvd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/iddp_rid.f
- delete mode 100644 scipy/linalg/src/id_dist/src/iddp_rsvd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/iddr_aid.f
- delete mode 100644 scipy/linalg/src/id_dist/src/iddr_asvd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/iddr_rid.f
- delete mode 100644 scipy/linalg/src/id_dist/src/iddr_rsvd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idz_frm.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idz_house.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idz_id.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idz_id2svd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idz_qrpiv.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idz_sfft.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idz_snorm.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idz_svd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idzp_aid.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idzp_asvd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idzp_rid.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idzp_rsvd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idzr_aid.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idzr_asvd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idzr_rid.f
- delete mode 100644 scipy/linalg/src/id_dist/src/idzr_rsvd.f
- delete mode 100644 scipy/linalg/src/id_dist/src/prini.f
-
-diff --git a/mypy.ini b/mypy.ini
-index 4417af39dc..4bdbdf9750 100644
---- a/mypy.ini
-+++ b/mypy.ini
-@@ -140,7 +140,7 @@ ignore_missing_imports = True
- [mypy-scipy.linalg._solve_toeplitz]
- ignore_missing_imports = True
- 
--[mypy-scipy.linalg._interpolative]
-+[mypy-scipy.linalg._decomp_interpolative]
- ignore_missing_imports = True
- 
- [mypy-scipy.optimize._group_columns]
-diff --git a/scipy/linalg/_decomp_interpolative.pyx b/scipy/linalg/_decomp_interpolative.pyx
-new file mode 100644
-index 000000000..e1a5b2a62
---- /dev/null
-+++ b/scipy/linalg/_decomp_interpolative.pyx
-@@ -0,0 +1,1992 @@
-+# cython: boundscheck=False
-+# cython: initializedcheck=False
-+# cython: wraparound=False
-+# cython: cdivision=True
-+# cython: cpow=True
-+
-+"""
-+This file is a Cython rewrite of the original Fortran code of "ID: A software package
-+for low-rank approximation of matrices via interpolative decompositions, Version 0.4",
-+written by Per-Gunnar Martinsson, Vladimir Rokhlin, Yoel Shkolnisky, and Mark Tygert.
-+
-+The original Fortran code can be found at the last author's current website
-+http://tygert.com/software.html
-+
-+
-+References
-+----------
-+
-+N. Halko, P.G. Martinsson, and J. A. Tropp, "Finding structure with randomness:
-+probabilistic algorithms for constructing approximate matrix decompositions",
-+SIAM Review, 53 (2011), pp. 217-288. DOI:10.1137/090771806
-+
-+H. Cheng, Z. Gimbutas, P.G. Martinsson, V.Rokhlin, "On the Compression of Low
-+Rank Matrices", SIAM Journal of Scientific Computing, 2005, Vol.26(4),
-+DOI:10.1137/030602678
-+
-+
-+
-+Copyright (C) 2024 SciPy developers
-+
-+Redistribution and use in source and binary forms, with or without
-+modification, are permitted provided that the following conditions are met:
-+
-+a. Redistributions of source code must retain the above copyright notice,
-+   this list of conditions and the following disclaimer.
-+b. Redistributions in binary form must reproduce the above copyright
-+   notice, this list of conditions and the following disclaimer in the
-+   documentation and/or other materials provided with the distribution.
-+c. Names of the SciPy Developers may not be used to endorse or promote
-+   products derived from this software without specific prior written
-+   permission.
-+
-+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
-+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-+OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
-+THE POSSIBILITY OF SUCH DAMAGE.
-+
-+
-+Notes
-+-----
-+
-+The translated functions from the original Fortran77 code are as follows (with various
-+internal functions subsumed into respective functions):
-+
-+    idd_diffsnorm
-+    idd_estrank
-+    idd_findrank
-+    idd_id2svd
-+    idd_ldiv
-+    idd_poweroftwo
-+    idd_reconid
-+    idd_snorm
-+    iddp_aid
-+    iddp_asvd
-+    iddp_id
-+    iddp_qrpiv
-+    iddp_rid
-+    iddp_rsvd
-+    iddp_svd
-+    iddr_aid
-+    iddr_asvd
-+    iddr_id
-+    iddr_qrpiv
-+    iddr_rid
-+    iddr_rsvd
-+    iddr_svd
-+    idz_diffsnorm
-+    idz_estrank
-+    idz_findrank
-+    idz_id2svd
-+    idz_reconid
-+    idz_snorm
-+    idzp_aid
-+    idzp_asvd
-+    idzp_id
-+    idzp_qrpiv
-+    idzp_rid
-+    idzp_rsvd
-+    idzp_svd
-+    idzr_aid
-+    idzr_asvd
-+    idzr_id
-+    idzr_rid
-+    idzr_rsvd
-+    idzr_qrpiv
-+    idzr_svd
-+
-+"""
-+
-+import numpy as np
-+from numpy.typing import NDArray
-+cimport numpy as cnp
-+cnp.import_array()
-+
-+from cpython.mem cimport PyMem_Free, PyMem_Malloc, PyMem_Realloc
-+from libc.math cimport hypot
-+
-+import scipy.linalg as la
-+from scipy.fft import rfft, fft
-+from scipy.sparse.linalg import LinearOperator
-+
-+from scipy.linalg.cython_lapack cimport dlarfgp, dorm2r, zunm2r, zlarfgp
-+from scipy.linalg.cython_blas cimport dnrm2, dtrsm, dznrm2, ztrsm
-+
-+
-+__all__ = ['idd_estrank', 'idd_ldiv', 'idd_poweroftwo', 'idd_reconid', 'iddp_aid',
-+           'iddp_asvd', 'iddp_id', 'iddp_qrpiv', 'iddp_svd', 'iddr_aid', 'iddr_asvd',
-+           'iddr_id', 'iddr_qrpiv', 'iddr_svd', 'idz_estrank', 'idz_reconid',
-+           'idzp_aid', 'idzp_asvd', 'idzp_id', 'idzp_qrpiv', 'idzp_svd', 'idzr_aid',
-+           'idzr_asvd', 'idzr_id', 'idzr_qrpiv', 'idzr_svd', 'idd_id2svd', 'idz_id2svd'
-+           # LinearOperator funcs
-+           'idd_findrank', 'iddp_rid', 'iddp_rsvd', 'iddr_rid', 'iddr_rsvd',
-+           'idz_findrank', 'idzp_rid', 'idzp_rsvd', 'idzr_rid', 'idzr_rsvd',
-+           'idd_snorm', 'idz_snorm', 'idd_diffsnorm', 'idz_diffsnorm'
-+           ]
-+
-+
-+def idd_diffsnorm(A: LinearOperator, B: LinearOperator, int its=20, rng=None):
-+    cdef int n = A.shape[1], j = 0, intone = 1
-+    cdef cnp.float64_t snorm = 0.0
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] v1
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] v2
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] u1
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] u2
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+    v1 = rng.uniform(low=-1., high=1., size=n)
-+    v1 /= dnrm2(&n, &v1[0], &intone)
-+
-+    for j in range(its):
-+        u1 = A.matvec(v1)
-+        u2 = B.matvec(v1)
-+        u1 -= u2
-+        v1 = A.rmatvec(u1)
-+        v2 = B.rmatvec(u1)
-+        v1 -= v2
-+
-+        snorm = dnrm2(&n, &v1[0], &intone)
-+        if snorm > 0.0:
-+            v1 /= snorm
-+
-+        snorm = np.sqrt(snorm)
-+
-+    return snorm
-+
-+
-+def idd_estrank(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a: NDArray, eps: float,
-+                rng=None):
-+    cdef int m = a.shape[0], n = a.shape[1]
-+    cdef int intone = 1, n2, nsteps = 3, row, r, nstep, cols, k, nulls
-+    cdef cnp.float64_t h, alpha, beta
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=3] albetas
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau_arr
-+    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] subselect
-+    cdef cnp.float64_t *aa
-+    cdef cnp.float64_t *ff
-+    cdef cnp.float64_t[:, ::1] Fmemview
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] giv2x2
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] rta
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] Fc
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] F
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+
-+    n2 = idd_poweroftwo(m)
-+
-+    # This part is the initialization that is done via idd_frmi
-+    # for a Subsampled Randomized Fourier Transfmrom (SRFT).
-+
-+    # Draw (nsteps x m x 2) arrays from [-1, 1) uniformly and scale
-+    # each 2-element row to unity norm
-+    albetas = rng.uniform(low=-1.0, high=1.0, size=[nsteps, m, 2])
-+    aa = cnp.PyArray_DATA(albetas)
-+    # Walk over every 2D row and normalize
-+    for r in range(0, 2*nsteps*m, 2):
-+        h = 1/hypot(aa[r], aa[r+1])
-+        aa[r] *= h
-+        aa[r+1] *= h
-+
-+    # idd_random_transf
-+    rta = a.copy()
-+
-+    # Rotate and shuffle "a" nsteps-many times
-+    giv2x2 = cnp.PyArray_ZEROS(2, [2, 2], cnp.NPY_FLOAT64, 0)
-+    for nstep in range(nsteps):
-+        for row in range(m-1):
-+            alpha, beta = albetas[nstep, row, 0], albetas[nstep, row, 1]
-+            giv2x2[0, 0] = alpha
-+            giv2x2[0, 1] = beta
-+            giv2x2[1, 0] = -beta
-+            giv2x2[1, 1] = alpha
-+            np.matmul(giv2x2, rta[row:row+2, :], out=rta[row:row+2, :])
-+
-+        rta = rta[rng.permutation(m), :]
-+
-+    # idd_subselect pick randomly n2-many rows
-+    subselect = rng.choice(m, n2, replace=False)
-+    rta = rta[subselect, :]
-+
-+    # Perform rfft on each column. Note that the first and the last
-+    # element of the result is real valued (n2 is power of 2).
-+    #
-+    # We view the complex valued entries as two consecutive doubles
-+    # (by also removing the 2nd and last all-0 rows -- see idd_frm).
-+    # Then after transpose we do a final row shuffle after transpose.
-+    Fc = rfft(rta.T, axis=1)
-+    # Move the first col to second col
-+    Fc[:, 0] *= 1.j
-+    # Perform the final permutation
-+    F = Fc.view(np.float64)[:, 1:-1].T[rng.permutation(n2), :]
-+
-+    Fcopy = F.copy()
-+    cols = F.shape[1]
-+    row = F.shape[0]
-+    sssmax = 0.
-+    ff = cnp.PyArray_DATA(F)
-+    for r in range(cols):
-+        h = dnrm2(&row, &ff[r], &cols)
-+        if h > sssmax:
-+            sssmax = h
-+
-+    tau_arr = cnp.PyArray_ZEROS(1, [cols], cnp.NPY_FLOAT64, 0)
-+    k, nulls = 0, 0
-+
-+    # In Fortran id_dist, F is transposed and works on the columns
-+    # Since we have a C-array we work directly on rows
-+    # The reflectors are overwritten on rows of F directly
-+    # Hence at any k'th step, we have
-+    #
-+    #            [ B  r  r  r  r  r  r  r ]
-+    #            [           ....         ]
-+    #            [           ....         ]
-+    #            [ x  x  x  B  r  r  r  r ]
-+    #            [ x  x  x  x  B  r  r  r ]
-+    #            [ x  x  x  x  x  B  r  r ]
-+    #            [ x  x  x  x  x  x  x  x ]
-+    #            [ x  x  x  x  x  x  x  x ]
-+    #
-+
-+    # Loop until nulls = 7, or krank+nulls = n2, or krank+nulls = n.
-+    Fmemview = F
-+    while (nulls < 7) and (k+nulls < min(n, n2)):
-+        # Apply previous Householder reflectors
-+        if k > 0:
-+            for kk in range(k):
-+                F[k, kk:] -= tau_arr[kk]*(F[kk, kk:] @ F[k, kk:])*F[kk, kk:]
-+
-+        # Get the next Householder reflector and store in F
-+        r = cols-k
-+        # n, alpha, x, incx, tau
-+        dlarfgp(&r, &Fmemview[k, k], &Fmemview[k, k+1], &intone, &tau_arr[k])
-+        beta = F[k, k]
-+        F[k, k] = 1
-+
-+        if (beta <= eps*sssmax):
-+            nulls += 1
-+        k += 1
-+
-+    if nulls < 7:
-+        k = 0
-+
-+    return k, Fcopy
-+
-+
-+def idd_findrank(A: LinearOperator, cnp.float64_t eps, rng=None):
-+    # Estimate the rank of A by repeatedly using A.rmatvec(random vec)
-+
-+    cdef int m = A.shape[0], n = A.shape[1], k = 0, kk = 0,r = n, krank
-+    cdef int no_of_cols = 4, intone = 1, info = 0
-+    cdef cnp.float64_t[::1] tau = cnp.PyArray_ZEROS(1, [min(m, n)], cnp.NPY_FLOAT64, 0)
-+    cdef cnp.float64_t[::1] y = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] retarr
-+
-+    # The size of the QR decomposition is rank dependent which is unknown
-+    # at runtime. Hence we don't want to allocate a dense version of the
-+    # linear operator which can be too big. Instead, a typical "realloc double
-+    # if run out of space" strategy is used here. Starts with 4*n
-+    # Also, we hold the A.T @ x results in a separate array to return
-+    # and do the same for that too.
-+    cdef cnp.float64_t *ra = PyMem_Malloc(
-+        sizeof(cnp.float64_t)*no_of_cols*n
-+        )
-+    cdef cnp.float64_t *reallocated_ra
-+    cdef cnp.float64_t *ret = PyMem_Malloc(
-+        sizeof(cnp.float64_t)*no_of_cols*n
-+        )
-+    cdef cnp.float64_t *reallocated_ret
-+    cdef cnp.float64_t enorm = 0.0
-+
-+    if (not ra) or (not ret):
-+        raise MemoryError("Failed to allocate at least required memory "
-+                          f"{no_of_cols*n*8} bytes for"
-+                          "'scipy.linalg.interpolative.idd_findrank()' "
-+                          "function.")
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+
-+    krank = 0
-+    try:
-+        while True:
-+
-+            # Generate random vector and rmatvec then save the result
-+            x = rng.uniform(size=m)
-+            y = A.rmatvec(x)
-+            for kk in range(n):
-+                ret[krank*n + kk] = y[kk]
-+
-+            if krank == 0:
-+                enorm = dnrm2(&n, &y[0], &intone)
-+            else:  # krank > 0
-+                # Transpose-Apply previous Householder reflectors, if any
-+                # SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, WORK, INFO
-+                dorm2r('L','T', &n, &intone, &krank, &ra[0], &n,
-+                       &tau[0], &y[0], &n, &ra[(no_of_cols-1)*n], &info)
-+
-+            # Get the next Householder reflector
-+            r = n-krank
-+            # N, ALPHA, X, INCX, TAU
-+            dlarfgp(&r, &y[krank], &y[krank+1], &intone, &tau[krank])
-+
-+            for kk in range(n):
-+                ra[krank*n + kk] = y[kk]
-+
-+            # Running out of space; try to double the size of ra
-+            if krank == (no_of_cols-2):
-+                reallocated_ra = PyMem_Realloc(
-+                    ra, sizeof(cnp.float64_t)*no_of_cols*n*2)
-+                reallocated_ret = PyMem_Realloc(
-+                    ret, sizeof(cnp.float64_t)*no_of_cols*n*2)
-+
-+                if reallocated_ra and reallocated_ret:
-+                    ra = reallocated_ra
-+                    ret = reallocated_ret
-+                    no_of_cols *= 2
-+                else:
-+                    raise MemoryError(
-+                        "'scipy.linalg.interpolative.idd_findrank()' failed to "
-+                        f"allocate the required memory,{no_of_cols*n*16} bytes "
-+                        "while trying to determine the rank (currently "
-+                        f"{krank}) of a LinearOperator with precision {eps}."
-+                    )
-+            krank += 1
-+            if (y[krank-1] < eps*enorm) or (krank >= min(m, n)):
-+                break
-+    finally:
-+        # Crashed or successfully ended up here
-+        # Discard Householder vectors
-+        PyMem_Free(ra)
-+        retarr = cnp.PyArray_EMPTY(2, [krank, n], cnp.NPY_FLOAT64, 0)
-+        for k in range(krank):
-+            for kk in range(n):
-+                retarr[k, kk] = ret[k*n+kk]
-+        PyMem_Free(ret)
-+
-+    return krank, retarr
-+
-+
-+def idd_id2svd(
-+    cnp.ndarray[cnp.float64_t, mode='c', ndim=2] cols,
-+    cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms,
-+    cnp.ndarray[cnp.float64_t, ndim=2] proj,
-+    ):
-+    cdef int m = cols.shape[0], krank = cols.shape[1]
-+    cdef int n = proj.shape[1] + krank, info, ci
-+    cdef cnp.ndarray[cnp.float64_t, mode='fortran', ndim=2] C
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau1
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau2
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] UU
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
-+    cdef cnp.ndarray[cnp.float64_t, ndim=2] V
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] VV
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] p
-+
-+    UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_FLOAT64, 0)
-+    VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_FLOAT64, 0)
-+    p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_FLOAT64, 0)
-+
-+    # idd_reconint
-+    for ci in range(krank):
-+        p[ci, perms[ci]] = 1.0
-+
-+    p[:, perms[krank:]] = proj[:, :]
-+
-+    inds1, tau1 = iddr_qrpiv(cols, krank)
-+    # idd_rinqr and idd_rearr
-+    r = np.triu(cols[:krank, :])
-+    for ci in range(krank-1, -1, -1):
-+        r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
-+
-+    t = p.T.copy()
-+    inds2, tau2 = iddr_qrpiv(t, krank)
-+    r2 = np.triu(t[:krank, :])
-+    for ci in range(krank-1, -1, -1):
-+        r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
-+
-+    r3 = r @ r2.T
-+    UU[:krank, :krank], S, V = la.svd(r3,
-+                                      full_matrices=False,
-+                                      check_finite=False)
-+
-+    # Apply Q of col to U from the left, use cols as scratch
-+    C = cols[:, :krank].copy(order='F')
-+    dorm2r('R', 'T',
-+           &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
-+           &UU[0,0], &krank, &cols[0, 0], &info)
-+
-+    VV[:krank, :krank] = V[:, :].T
-+    # Apply Q of t to V from the left
-+    C = t[:, :krank].copy(order='F')
-+    dorm2r('R', 'T',
-+           &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
-+           &VV[0, 0], &krank, &cols[0, 0], &info)
-+
-+    return UU, S, VV
-+
-+
-+cdef inline int idd_ldiv(int l, int n) noexcept nogil:
-+    cdef int m = l
-+    while (n % m != 0):
-+        m -= 1
-+    return m
-+
-+
-+cdef int idd_poweroftwo(int m) noexcept nogil:
-+    """
-+    Find the integer solution to l = floor(log2(m))
-+    """
-+    cdef int n = 1
-+    while (n < m):
-+        n <<= 1  # Times 2
-+    return n >> 1  # Divide by 2
-+
-+
-+def idd_reconid(B, idx, proj):
-+    cdef int m = B.shape[0], krank = B.shape[1]
-+    cdef int n = len(idx)
-+    approx = np.zeros([m, n], dtype=np.float64)
-+
-+    approx[:, idx[:krank]] = B
-+    approx[:, idx[krank:]] = B @ proj
-+
-+    return approx
-+
-+
-+def idd_snorm(A: LinearOperator, int its=20, rng=None):
-+    cdef int n = A.shape[1]
-+    cdef int j = 0, intone = 1
-+    cdef cnp.float64_t snorm = 0.0
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] v
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] u
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+    v = rng.uniform(low=-1., high=1., size=n)
-+    v /= dnrm2(&n, &v[0], &intone)
-+
-+    for j in range(its):
-+        u = A.matvec(v)
-+        v = A.rmatvec(u)
-+        snorm = dnrm2(&n, &v[0], &intone)
-+        if snorm > 0.0:
-+            v /= snorm
-+
-+        snorm = np.sqrt(snorm)
-+
-+    return snorm
-+
-+
-+def iddp_aid(cnp.ndarray[cnp.float64_t, ndim=2] a: NDArray, eps: float, rng=None):
-+    krank, proj = idd_estrank(a, eps, rng=rng)
-+    if krank != 0:
-+        proj = proj[:krank, :]
-+        return iddp_id(proj, eps=eps)
-+
-+    return iddp_id(a, eps=eps)
-+
-+
-+def iddp_asvd(cnp.ndarray[cnp.float64_t, ndim=2] a: NDArray, eps: float, rng=None):
-+    cdef int m = a.shape[0], n = a.shape[1]
-+    cdef int krank, info, ci
-+    cdef cnp.ndarray[cnp.float64_t, mode='fortran', ndim=2] C
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau1
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau2
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] UU
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
-+    cdef cnp.ndarray[cnp.float64_t, ndim=2] V
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] VV
-+    cdef cnp.ndarray[cnp.float64_t, ndim=2] proj
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] perms
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] p
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] col
-+
-+    krank, perms, proj = iddp_aid(a.copy(), eps, rng=rng)
-+
-+    if krank > 0:
-+        UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_FLOAT64, 0)
-+        VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_FLOAT64, 0)
-+
-+        p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_FLOAT64, 0)
-+        col = a[:, perms[:krank]].copy()
-+
-+        # idd_reconint
-+        for ci in range(krank):
-+            p[ci, perms[ci]] = 1.0
-+
-+        # p[np.arange(krank), perms[:krank]] = 1.
-+        p[:, perms[krank:]] = proj[:, :]
-+
-+        inds1, tau1 = iddr_qrpiv(col, krank)
-+        # idd_rinqr and idd_rearr
-+        r = np.triu(col[:krank, :])
-+        for ci in range(krank-1, -1, -1):
-+            r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
-+
-+        t = p.T.copy()
-+        inds2, tau2 = iddr_qrpiv(t, krank)
-+        r2 = np.triu(t[:krank, :])
-+        for ci in range(krank-1, -1, -1):
-+            r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
-+
-+        r3 = r @ r2.T
-+        UU[:krank, :krank], S, V = la.svd(r3, full_matrices=False)
-+
-+        # Apply Q of col to U from the left
-+        C = col[:, :krank].copy(order='F')
-+        dorm2r('R', 'T',
-+               &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
-+               &UU[0,0], &krank, &a[0, 0], &info)
-+
-+        VV[:krank, :krank] = V[:, :].T
-+        # Apply Q of t to V from the left
-+        C = t[:, :krank].copy(order='F')
-+        dorm2r('R', 'T',
-+               &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
-+               &VV[0, 0], &krank, &a[0, 0], &info)
-+
-+    return UU, S, VV
-+
-+
-+def iddp_id(cnp.ndarray[cnp.float64_t, ndim=2] a: NDArray, eps: float):
-+    cdef int n = a.shape[1], krank, tmp_int, p
-+    cdef cnp.float64_t one = 1
-+    krank, _, inds = iddp_qrpiv(a, eps)
-+
-+    # Change pivots to permutation
-+    perms = cnp.PyArray_ZEROS(1, [n], cnp.NPY_INT64, 0)
-+    for p in range(n):
-+        perms[p] = p
-+
-+    if krank > 0:
-+        for p in range(krank):
-+            # Apply pivots
-+            tmp_int = perms[p]
-+            perms[p] = perms[inds[p]]
-+            perms[inds[p]] = tmp_int
-+            # perms[[p, inds[p]]] = perms[[inds[p], p]]
-+
-+    # Let A = [A1, A2] and A1 has krank cols and upper triangular.
-+    # Find X that satisfies A1 @ X = A2
-+    # In SciPy.linalg this amounts to;
-+    #
-+    # proj = la.solve_triangular(a[:krank, :krank], a[:krank, krank:],
-+    #                            lower=False, check_finite=False)
-+    #
-+    # Push into BLAS without transposes.
-+    # A1 = a[:krank, :krank]
-+    # A2 = a[:krank, krank:]
-+    # Instead solve X @ A1.T = A2.T
-+    # Fortran already sees A1 as A1.T and becomes lower tri, side = R
-+
-+    tmp_int = n - krank
-+    # SIDE,UPLO,TRANSA,DIAG,M,N,ALPHA,A,LDA,B,LDB
-+    dtrsm('R', 'L', 'N', 'N',
-+          &tmp_int, &krank, &one, &a[0, 0], &n, &a[0, krank], &n)
-+
-+    return krank, np.array(perms), a[:krank, krank:]
-+
-+
-+def iddp_qrpiv(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a, cnp.float64_t eps):
-+    """
-+    This is a minimal version of ?GEQP3 from LAPACK with an
-+    additional early stopping criterion over given precision.
-+
-+    This function overwrites entries of "a" !
-+    """
-+
-+    cdef int m = a.shape[0], n = a.shape[1]
-+    cdef cnp.ndarray col_norms = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
-+    cdef int k = 0, kpiv = 0, i = 0, tmp_int = 0, int_n = 0
-+    cdef cnp.float64_t tmp_sca = 0.
-+    cdef cnp.ndarray taus = cnp.PyArray_ZEROS(1, [m], cnp.NPY_FLOAT64, 0)
-+    cdef cnp.ndarray ind = cnp.PyArray_ZEROS(1, [n], cnp.NPY_INT64, 0)
-+    cdef cnp.float64_t[::1] taus_v = taus
-+    cdef cnp.float64_t feps = 0.1e-16  # np.finfo(np.float64).eps
-+    cdef cnp.float64_t ssmax, ssmaxin
-+    cdef int nupdate = 0
-+
-+    for i in range(n):
-+        col_norms[i] = dnrm2(&m, &a[0, i], &n)**2
-+
-+    kpiv = np.argmax(col_norms)
-+    ssmax = col_norms[kpiv]
-+    ssmaxin = ssmax
-+
-+    for k in range(min(m, n)):
-+
-+        # Pivoting
-+        ind[k] = kpiv
-+        # Swap columns a[:, k] and a[:, kpiv]
-+        a[:, [kpiv, k]] = a[:, [k, kpiv]]
-+
-+        # Swap col_norms[krank] and col_norms[kpiv]
-+        col_norms[[kpiv, k]] = col_norms[[k, kpiv]]
-+
-+        if k < m-1:
-+            # Compute the householder reflector for column k
-+            tmp_sca = a[k, k]
-+            # FIX: Convert these to F_INT
-+            tmp_int = (m - k)
-+            int_n = n
-+            dlarfgp(&tmp_int, &tmp_sca, &a[k+1, k], &int_n, &taus_v[k])
-+
-+            # Overwrite with 1. for easy matmul
-+            a[k, k] = 1
-+            if k < n-1:
-+                # Apply the householder reflector to the rest on the right
-+                a[k:, k+1:] -= np.outer(taus[k]*a[k:, k], a[k:, k] @ a[k:, k+1:])
-+
-+            # Put back the beta in place
-+            a[k, k] = tmp_sca
-+
-+            # Update the norms
-+            col_norms[k] = 0
-+            col_norms[k+1:] -= a[k, k+1:]**2
-+            ssmax = 0
-+            kpiv = k+1
-+            if k < n-1:
-+                kpiv = np.argmax(col_norms[k+1:]) + (k + 1)
-+                ssmax = col_norms[kpiv]
-+
-+            if (((ssmax < 1000*feps*ssmaxin) and (nupdate == 0)) or
-+                    ((ssmax < ((1000*feps)**2)*ssmaxin) and (nupdate == 1))):
-+                nupdate += 1
-+                ssmax = 0
-+                kpiv = k+1
-+
-+                if k < n-1:
-+                    for i in range(k+1, n):
-+                        tmp_int = m-k-1
-+                        col_norms[i] = dnrm2(&tmp_int, &a[k+1, i], &n)**2
-+                    kpiv = np.argmax(col_norms[k+1:]) + (k + 1)
-+                    ssmax = col_norms[kpiv]
-+        if (ssmax <= (eps**2)*ssmaxin):
-+            break
-+    # a is overwritten; return numerical rank and pivots
-+    return k + 1, taus, ind
-+
-+
-+def iddp_rid(A: LinearOperator, cnp.float64_t eps, rng=None):
-+    _, ret = idd_findrank(A, eps, rng)
-+    return iddp_id(ret, eps)
-+
-+
-+def iddp_rsvd(A: LinearOperator, cnp.float64_t eps, rng=None):
-+    cdef int n = A.shape[1]
-+    cdef int krank, j
-+    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms
-+    cdef cnp.ndarray[cnp.float64_t, ndim=2] proj
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] col
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] x
-+
-+    krank, perms, proj = iddp_rid(A, eps, rng)
-+    if krank > 0:
-+        # idd_getcols
-+        col = cnp.PyArray_EMPTY(2, [n, krank], cnp.NPY_FLOAT64, 0)
-+        x = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
-+
-+        for j in range(krank):
-+            x[perms[j]] = 1.
-+            col[:, j] = A.matvec(x)
-+            x[perms[j]] = 0.
-+
-+        return idd_id2svd(cols=col, perms=perms, proj=proj)
-+
-+    # TODO: figure out empty return
-+    return None
-+
-+
-+def iddp_svd(cnp.ndarray[cnp.float64_t, ndim=2] a: NDArray, eps: float):
-+    """a is overwritten"""
-+    cdef int m = a.shape[0], krank, info
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] taus
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] UU
-+    cdef cnp.ndarray[cnp.float64_t, mode='fortran', ndim=2] C
-+
-+    # Get the pivoted QR
-+    krank, taus, inds = iddp_qrpiv(a, eps)
-+
-+    if krank > 0:
-+        r = np.triu(a[:krank, :])
-+        # Apply pivots in reverse
-+        for p in range(krank-1, -1, -1):
-+            r[:, [p, inds[p]]] = r[:, [inds[p], p]]
-+
-+        # JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO
-+        # dgesvd('S', 'O', &krank, &n)
-+        U, S, V = la.svd(r, full_matrices=False)
-+
-+        # Apply Q to U via dorm2r
-+        # Possibly U is shorter than Q
-+        UU = np.zeros([m, krank], dtype=a.dtype)
-+        UU[:krank, :krank] = U
-+        # Do the transpose dance for C-layout, use a for scratch
-+        C = a[:, :krank].copy(order='F')
-+        dorm2r('R', 'T',
-+               &krank, &m, &krank, &C[0, 0], &m, &taus[0],
-+               &UU[0,0], &krank, &a[0, 0], &info)
-+
-+    return UU, S, V
-+
-+
-+def iddr_aid(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a: NDArray, int krank,
-+             rng=None):
-+    cdef int m = a.shape[0], n = a.shape[1], n2, nsteps = 3, row, r, nstep, L
-+    cdef cnp.float64_t h, alpha, beta
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=3] albetas
-+    cdef cnp.ndarray[cnp.npy_int64, mode='c', ndim=1] subselect
-+    cdef cnp.float64_t *aa
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] giv2x2
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] rta
-+    cdef cnp.ndarray[cnp.npy_int64, mode='c', ndim=1] marker
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+
-+    # idd_aidi
-+    L = krank + 8
-+    n2 = 0
-+    if (L >= n2) or (L > m):
-+        inds, proj = iddr_id(a, krank)
-+        return inds, proj
-+
-+    n2 = idd_poweroftwo(m)
-+
-+    # idd_sfrmi
-+    # idd_pairsamps
-+    ind = rng.permutation(n2)
-+    ind2 = cnp.PyArray_ZEROS(1, [L], cnp.NPY_INT64, 0)
-+
-+    marker = cnp.PyArray_ZEROS(1, [n2//2], cnp.NPY_INT64, 0)
-+    for k in range(L):
-+        marker[(ind[k]+1)//2] = marker[(ind[k]+1)//2]+1
-+
-+    for r in range(n2//2):
-+        if marker[r] != 0:
-+            l2 += 1
-+            ind2[r] = r
-+
-+    # Draw (nsteps x m x 2) arrays from [-1, 1) uniformly and scale
-+    # each 2-element row to unity norm
-+    albetas = rng.uniform(low=-1.0, high=1.0, size=[nsteps, m, 2])
-+    aa = cnp.PyArray_DATA(albetas)
-+    # Walk over every 2D row and normalize
-+    for r in range(0, 2*nsteps*m, 2):
-+        # ignoring the improbable zero generation by rng.uniform
-+        h = 1.0/hypot(aa[r], aa[r+1])
-+        aa[r] *= h
-+        aa[r+1] *= h
-+
-+    # idd_random_transf
-+    rta = a.copy()
-+
-+    # Rotate and shuffle "a" nsteps-many times
-+    giv2x2 = cnp.PyArray_ZEROS(2, [2, 2], cnp.NPY_FLOAT64, 0)
-+    for nstep in range(nsteps):
-+        for row in range(m-1):
-+            alpha, beta = albetas[nstep, row, 0], albetas[nstep, row, 1]
-+            giv2x2[0, 0] = alpha
-+            giv2x2[0, 1] = beta
-+            giv2x2[1, 0] = -beta
-+            giv2x2[1, 1] = alpha
-+            np.matmul(giv2x2, rta[row:row+2, :], out=rta[row:row+2, :])
-+
-+        rta = rta[rng.permutation(m), :]
-+
-+    # idd_subselect pick randomly n2-many rows
-+    subselect = rng.choice(m, n2, replace=False)
-+    rta = rta[subselect, :]
-+
-+    # idd_sffti
-+    twopi = 2*np.pi
-+    twopii = twopi*1.j
-+    nblock = idd_ldiv(l2, n2)
-+    fact = 1/np.sqrt(n2)
-+
-+    if l2 == 1:
-+        wsave = np.exp(-twopii*k*ind2[0]/np.arange(1, n2+1))*fact
-+    else:
-+        m = n2//nblock
-+
-+        wsave = np.empty(m*l2, dtype=complex)
-+        for j in range(l2):
-+            i = ind2[j]
-+            if (i+1) <= (n//2 - m//2):
-+                idivm = i // m
-+                imodm = i - m*idivm
-+                for k in range(m):
-+                    wsave[m*j+k] = (
-+                        np.exp(-twopii*(k)*imodm/m)*
-+                        np.exp(-twopii*(k)*(idivm+1)/n)*
-+                        fact
-+                        )
-+            else:
-+                idivm = (i+1)//(m//2)
-+                imodm = (i+1)-(m//2)*idivm
-+                for k in range(m):
-+                    wsave[m*j+k] = np.exp(-twopii*(k-1)*imodm/m)*fact
-+
-+    # idd_sfft.f
-+    # There is some significant index olympics happening in the original Fortran code
-+    # however I could not reverse engineer it to understand what is happening and kept
-+    # as is with all its cryptic movements and their performance hits.
-+    # See DOI:10.1016/j.acha.2007.12.002 - Section 3.3
-+
-+    # Perform partial FFT to each nblock
-+    F = rfft(rta.reshape(nblock, m, -1), order='F', axis=0)
-+    # Roll the first entry to the last in the first axis for
-+    # the real frequency components. (faster than np.roll)
-+    F = F[[x for x in range(1, F.shape[0])] + [0], :, :]
-+    # Convert back to 2D array
-+    F = F.reshape(F.shape[0]*F.shape[1], -1)
-+
-+    csum = np.zeros_like(F[0, :])
-+    rsum = np.zeros_like(F[0, :])
-+
-+    for j in range(l2):
-+        i = ind2[j]
-+        if (i+1) <= (n//2 - m//2):
-+            idivm = i // m
-+            imodm = i - m*idivm
-+            csum[:] = 0.0
-+            for k in range(m):
-+                csum += F[m*idivm+k, :] * wsave[m*j+k]
-+            rta[2*i, :] = csum.real
-+            rta[2*i+1, :] = csum.imag
-+
-+        else:
-+            idivm = (i+1)//(m//2)
-+            imodm = (i+1)-(m//2)*idivm
-+            csum[:] = 0.0
-+            for k in range(m):
-+                csum += F[m*(nblock//2)+k, :] * wsave[m*j+k]
-+            rta[2*i, :] = csum.real
-+            rta[2*i+1, :] = csum.imag
-+            if i == (n//2) - 1:
-+                for k in range(m):
-+                    rsum += F[m*(nblock//2)+k, :]
-+                rta[n-2, :] = rsum
-+                rta[n-2, :] *= fact
-+
-+                rsum[:] = 0.0
-+                for k in range(m//2):
-+                    rsum += F[m*(nblock//2)+2*k-1]
-+                    rsum -= F[m*(nblock//2)+2*k]
-+                rta[n-1, :] = rsum
-+                rta[n-1, :] *= fact
-+
-+    # idd_subselect pick randomly l2-many rows
-+    subselect = rng.choice(n2, l2, replace=False)
-+    rta = rta[subselect, :]
-+
-+    perms, proj = iddr_id(rta, krank)
-+
-+    return perms, proj
-+
-+
-+def iddr_asvd(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a: NDArray, int krank,
-+              rng=None):
-+    cdef int m = a.shape[0], n = a.shape[1]
-+    cdef int info, ci
-+    cdef cnp.ndarray[cnp.float64_t, mode='fortran', ndim=2] C
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau1
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] tau2
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] UU
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
-+    cdef cnp.ndarray[cnp.float64_t, ndim=2] V
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] VV
-+    cdef cnp.ndarray[cnp.float64_t, ndim=2] proj
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] perms
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] p
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] col
-+
-+    perms, proj = iddr_aid(a.copy(), krank=krank, rng=rng)
-+
-+    UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_FLOAT64, 0)
-+    VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_FLOAT64, 0)
-+
-+    p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_FLOAT64, 0)
-+    col = a[:, perms[:krank]].copy()
-+
-+    # idd_reconint
-+    for ci in range(krank):
-+        p[ci, perms[ci]] = 1.0
-+
-+    p[:, perms[krank:]] = proj[:, :]
-+
-+    inds1, tau1 = iddr_qrpiv(col, krank)
-+    # idd_rinqr and idd_rearr
-+    r = np.triu(col[:krank, :])
-+    for ci in range(krank-1, -1, -1):
-+        r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
-+
-+    t = p.T.copy()
-+    inds2, tau2 = iddr_qrpiv(t, krank)
-+    r2 = np.triu(t[:krank, :])
-+    for ci in range(krank-1, -1, -1):
-+        r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
-+
-+    r3 = r @ r2.T
-+    UU[:krank, :krank], S, V = la.svd(r3, full_matrices=False)
-+
-+    # Apply Q of col to U from the left
-+    C = col[:, :krank].copy(order='F')
-+    dorm2r('R', 'T',
-+           &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
-+           &UU[0,0], &krank, &a[0, 0], &info)
-+
-+    VV[:krank, :krank] = V[:, :].T
-+    # Apply Q of t to V from the left
-+    C = t[:, :krank].copy(order='F')
-+    dorm2r('R', 'T',
-+           &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
-+           &VV[0, 0], &krank, &a[0, 0], &info)
-+
-+    return UU, S, VV
-+
-+
-+def iddr_id(cnp.ndarray[cnp.float64_t, ndim=2] a, int krank):
-+    cdef int n = a.shape[1]
-+    cdef int tmp_int
-+    cdef cnp.float64_t one = 1.0
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] perms
-+
-+    inds, _ = iddr_qrpiv(a, krank)
-+    perms = cnp.PyArray_Arange(0, n, 1, cnp.NPY_INT64)
-+
-+    if krank > 0:
-+        for p in range(krank):
-+            # Apply pivots
-+            tmp_int = perms[p]
-+            perms[p] = perms[inds[p]]
-+            perms[inds[p]] = tmp_int
-+
-+    # See iddp_id comments for below
-+    tmp_int = n - krank
-+    # SIDE,UPLO,TRANSA,DIAG,M,N,ALPHA,A,LDA,B,LDB
-+    dtrsm('R', 'L', 'N', 'N',
-+          &tmp_int, &krank, &one, &a[0, 0], &n, &a[0, krank], &n)
-+
-+    return perms, a[:krank, krank:]
-+
-+
-+def iddr_qrpiv(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a: NDArray, krank: int):
-+    cdef int m = a.shape[0], n = a.shape[1]
-+    cdef cnp.ndarray col_norms = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
-+    cdef int loop = 0, loops, kpiv = 0, i = 0, tmp_int = 0, int_n = 0
-+    cdef cnp.float64_t tmp_sca = 0.
-+    cdef cnp.ndarray taus = cnp.PyArray_ZEROS(1, [m], cnp.NPY_FLOAT64, 0)
-+    cdef cnp.ndarray ind = cnp.PyArray_ZEROS(1, [n], cnp.NPY_INT64, 0)
-+    cdef cnp.float64_t[::1] taus_v = taus
-+    cdef cnp.float64_t feps = 0.1e-16  # np.finfo(np.float64).eps
-+    cdef cnp.float64_t ssmax, ssmaxin
-+    cdef int nupdate = 0
-+
-+    loops = min(krank, min(m, n))
-+    for i in range(n):
-+        col_norms[i] = dnrm2(&m, &a[0, i], &n)**2
-+
-+    kpiv = np.argmax(col_norms)
-+    ssmax = col_norms[kpiv]
-+    ssmaxin = ssmax
-+
-+    for loop in range(loops):
-+
-+        ind[loop] = kpiv
-+        # Swap columns a[:, k] and a[:, kpiv]
-+        a[:, [kpiv, loop]] = a[:, [loop, kpiv]]
-+        # Swap col_norms[krank] and col_norms[kpiv]
-+        col_norms[[kpiv, loop]] = col_norms[[loop, kpiv]]
-+
-+        if loop < m-1:
-+            tmp_sca = a[loop, loop]
-+            # FIX: Convert these to F_INT
-+            tmp_int = (m - loop)
-+            int_n = n
-+            dlarfgp(&tmp_int, &tmp_sca, &a[loop+1, loop], &int_n, &taus_v[loop])
-+
-+            # Overwrite with 1. for easy matmul
-+            a[loop, loop] = 1
-+            if loop < n-1:
-+                # Apply the householder reflector to the rest on the right
-+                a[loop:, loop+1:] -= np.outer(taus[loop]*a[loop:, loop],
-+                                              a[loop:, loop] @ a[loop:, loop+1:])
-+
-+            # Put back the beta in place
-+            a[loop, loop] = tmp_sca
-+
-+            # Update the norms
-+            col_norms[loop] = 0
-+            col_norms[loop+1:] -= a[loop, loop+1:]**2
-+            ssmax = 0
-+            kpiv = loop+1
-+
-+            if loop < n-1:
-+                kpiv = np.argmax(col_norms[loop+1:]) + (loop + 1)
-+                ssmax = col_norms[kpiv]
-+            if (((ssmax < 1000*feps*ssmaxin) and (nupdate == 0)) or
-+                    ((ssmax < ((1000*feps)**2)*ssmaxin) and (nupdate == 1))):
-+                nupdate += 1
-+                ssmax = 0
-+                kpiv = loop+1
-+
-+                if loop < n-1:
-+                    for i in range(loop+1, n):
-+                        tmp_int = m-loop-1
-+                        col_norms[i] = dnrm2(&tmp_int, &a[loop+1, i], &n)**2
-+                    kpiv = np.argmax(col_norms[loop+1:]) + (loop + 1)
-+                    ssmax = col_norms[kpiv]
-+
-+    return ind, taus
-+
-+
-+def iddr_rid(A: LinearOperator, int krank, rng=None):
-+    cdef int m = A.shape[0], n = A.shape[1], k = 0
-+    cdef int L = min(krank+2, min(m, n))
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] r
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+
-+    r = cnp.PyArray_EMPTY(2, [L, n], cnp.NPY_FLOAT64, 0)
-+    for k in range(L):
-+        r[k, :] = A.rmatvec(rng.uniform(size=m))
-+
-+    return iddr_id(a=r, krank=krank)
-+
-+
-+def iddr_rsvd(A: LinearOperator, int krank, rng=None):
-+    cdef int n = A.shape[1], j
-+    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms
-+    cdef cnp.ndarray[cnp.float64_t, ndim=2] proj
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] col
-+
-+    perms, proj = iddr_rid(A, krank, rng)
-+    # idd_getcols
-+    col = cnp.PyArray_EMPTY(2, [n, krank], cnp.NPY_FLOAT64, 0)
-+    x = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
-+    for j in range(krank):
-+        x[perms[j]] = 1.
-+        col[:, j] = A.matvec(x)
-+        x[perms[j]] = 0.
-+
-+    return idd_id2svd(cols=col, perms=perms, proj=proj)
-+
-+
-+def iddr_svd(cnp.ndarray[cnp.float64_t, mode="c", ndim=2] a: NDArray, int krank):
-+    cdef int m = a.shape[0], info = 0
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] taus
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] UU
-+    cdef cnp.ndarray[cnp.float64_t, mode='fortran', ndim=2] C
-+
-+    # Get the pivoted QR
-+    inds, taus = iddr_qrpiv(a, krank)
-+
-+    r = np.triu(a[:krank, :])
-+    # Apply pivots in reverse
-+    for p in range(krank-1, -1, -1):
-+        r[:, [p, inds[p]]] = r[:, [inds[p], p]]
-+
-+    # JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO
-+    # dgesvd('S', 'O', &krank, &n)
-+    U, S, V = la.svd(r, full_matrices=False)
-+
-+    # Apply Q to U via dorm2r
-+    # Possibly U is shorter than Q
-+    UU = np.zeros([m, krank], dtype=a.dtype)
-+    UU[:krank, :krank] = U
-+    # Do the transpose dance for C-layout, use a for scratch
-+    C = a[:, :krank].copy(order='F')
-+    dorm2r('R', 'T',
-+           &krank, &m, &krank, &C[0, 0], &m, &taus[0],
-+           &UU[0,0], &krank, &a[0, 0], &info)
-+
-+    return UU, S, V
-+
-+
-+def idz_diffsnorm(A: LinearOperator, B: LinearOperator, int its=20, rng=None):
-+    cdef int n = A.shape[1], j = 0, intone = 1
-+    cdef cnp.float64_t snorm = 0.0
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] v1
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] v2
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] u1
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] u2
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+    v1 = rng.uniform(low=-1, high=1, size=(n, 2)).view(np.complex128).ravel()
-+    v1 /= dznrm2(&n, &v1[0], &intone)
-+
-+    for j in range(its):
-+        u1 = A.matvec(v1)
-+        u2 = B.matvec(v1)
-+        u1 -= u2
-+        v1 = A.rmatvec(u1)
-+        v2 = B.rmatvec(u1)
-+        v1 -= v2
-+
-+        snorm = dznrm2(&n, &v1[0], &intone)
-+        if snorm > 0.0:
-+            v1 /= snorm
-+
-+        snorm = np.sqrt(snorm)
-+
-+    return snorm
-+
-+
-+def idz_estrank(cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] a: NDArray, eps: float,
-+                rng=None):
-+    cdef int m = a.shape[0], n = a.shape[1], n2, nsteps = 3, row, r, nstep, cols, k
-+    cdef cnp.float64_t h, alpha, beta
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=3] albetas
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau_arr
-+    cdef cnp.ndarray[cnp.npy_int64, mode='c', ndim=1] subselect
-+    cdef double complex[:, ::1] ff
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=2] giv2x2
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] rta
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] F
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+
-+    n2 = idd_poweroftwo(m)
-+    # This part is the initialization that is done via idz_frmi
-+    # for a Subsampled Randomized Fourier Transfmrom (SRFT).
-+
-+    # Draw (nsteps x m x 4) array from [0, 2)*pi uniformly for
-+    # random points on complex unit circle and unitary rotations
-+    albetas = np.empty([nsteps, m, 4])
-+    albetas[:, :, 2:] = rng.uniform(low=0.0, high=2.0, size=[nsteps, m, 2])
-+    albetas[:, :, 2:] *= np.pi
-+    np.cos(albetas[:, :, 2], out=albetas[:, :, 0])
-+    np.sin(albetas[:, :, 2], out=albetas[:, :, 1])
-+    np.cos(albetas[:, :, 3], out=albetas[:, :, 2])
-+    np.sin(albetas[:, :, 3], out=albetas[:, :, 3])
-+
-+    # idd_random_transf
-+    rta = a.copy()
-+
-+    # Rotate and shuffle "a" nsteps-many times
-+    giv2x2 = cnp.PyArray_ZEROS(2, [2, 2], cnp.NPY_FLOAT64, 0)
-+    for nstep in range(nsteps):
-+        # Multiply with a point on the unit circle
-+        rta *= albetas[nstep, :, 2:].view(np.complex128)
-+        # Rotate
-+        for row in range(m-1):
-+            alpha, beta = albetas[nstep, row, 0], albetas[nstep, row, 1]
-+            giv2x2[0, 0] = alpha
-+            giv2x2[0, 1] = beta
-+            giv2x2[1, 0] = -beta
-+            giv2x2[1, 1] = alpha
-+            np.matmul(giv2x2, rta[row:row+2, :], out=rta[row:row+2, :])
-+
-+        rta = rta[rng.permutation(m), :]
-+
-+    # idd_subselect pick randomly n2-many rows
-+    subselect = rng.choice(m, n2, replace=False)
-+    rta = rta[subselect, :]
-+    # Perform rfft on each column.
-+    F = fft(rta, axis=0)[rng.permutation(n2), :]
-+
-+    Fcopy = F.copy()
-+    cols = F.shape[1]
-+    row = F.shape[0]
-+    sssmax = 0.
-+
-+    for r in range(cols):
-+        h = dznrm2(&row, &F[0, r], &cols)
-+        if h > sssmax:
-+            sssmax = h
-+
-+    tau_arr = cnp.PyArray_ZEROS(1, [cols], cnp.NPY_COMPLEX128, 0)
-+    k, nulls = 0, 0
-+    ff = F
-+    # Loop until nulls = 7, or krank+nulls = n2, or krank+nulls = n.
-+    while (nulls < 7) and (k+nulls < min(n, n2)):
-+        # Apply previous Householder reflectors
-+        if k > 0:
-+            for kk in range(k):
-+                F[k, kk:] -= (
-+                    np.conj(tau_arr[kk])*
-+                    (F[kk, kk:].conj() @ F[k, kk:])*
-+                    F[kk, kk:]
-+                    )
-+
-+        # Get the next Householder reflector and store in F
-+        r = cols-k
-+        row = 1
-+        zlarfgp(&r, &ff[k, k], &ff[k, k+1], &row, &tau_arr[k])
-+        if (np.abs(F[k, k]) <= eps*sssmax):
-+            nulls += 1
-+        F[k, k] = 1
-+        k += 1
-+
-+    if nulls < 7:
-+        k = 0
-+
-+    return k, Fcopy
-+
-+
-+def idz_findrank(A: LinearOperator, cnp.float64_t eps, rng=None):
-+    # Estimate the rank of A by repeatedly using A.rmatvec(random vec)
-+
-+    cdef int m = A.shape[0], n = A.shape[1], k = 0, kk = 0,r = n, krank
-+    cdef int no_of_cols = 4, intone = 1, info = 0
-+    cdef cnp.complex128_t[::1] tau = cnp.PyArray_ZEROS(1, [min(m, n)],
-+                                                       cnp.NPY_COMPLEX128, 0)
-+    cdef cnp.complex128_t[::1] y = cnp.PyArray_ZEROS(1, [n], cnp.NPY_COMPLEX128, 0)
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] retarr
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] x
-+
-+    # The size of the QR decomposition is rank dependent which is unknown
-+    # at runtime. Hence we don't want to allocate a dense version of the
-+    # linear operator which can be too big. Instead, a typical "realloc double
-+    # if run out of space" strategy is used here. Starts with 4*n
-+    # Also, we hold the A.T @ x results in a separate array to return
-+    # and do the same for that too.
-+    cdef cnp.complex128_t *ra = PyMem_Malloc(
-+        sizeof(cnp.complex128_t)*no_of_cols*n
-+        )
-+    cdef cnp.complex128_t *reallocated_ra
-+    cdef cnp.complex128_t *ret = PyMem_Malloc(
-+        sizeof(cnp.complex128_t)*no_of_cols*n
-+        )
-+    cdef cnp.complex128_t *reallocated_ret
-+    cdef cnp.complex128_t enorm = 0.0
-+
-+    if (not ra) or (not ret):
-+        raise MemoryError("Failed to allocate at least required memory "
-+                          f"{no_of_cols*n*8} bytes for"
-+                          "'scipy.linalg.interpolative.idz_findrank()' "
-+                          "function.")
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+
-+    krank = 0
-+    try:
-+        while True:
-+
-+            # Generate random vector and rmatvec then save the result
-+            x = rng.uniform(size=(m,2)).view(np.complex128).ravel()
-+            y = A.rmatvec(x)
-+
-+            for kk in range(n):
-+                ret[krank*n + kk] = y[kk]
-+
-+            if krank == 0:
-+                enorm = dznrm2(&n, &y[0], &intone)
-+            else:  # krank > 0
-+                # Transpose-Apply previous Householder reflectors, if any
-+                # SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC, WORK, INFO
-+                zunm2r('L','C', &n, &intone, &krank, &ra[0], &n,
-+                       &tau[0], &y[0], &n, &ra[(no_of_cols-1)*n], &info)
-+
-+            # Get the next Householder reflector
-+            r = n-krank
-+            # N, ALPHA, X, INCX, TAU
-+            zlarfgp(&r, &y[krank], &y[krank+1], &intone, &tau[krank])
-+
-+            for kk in range(n):
-+                ra[krank*n + kk] = y[kk]
-+
-+            # Running out of space; try to double the size of ra
-+            if krank == (no_of_cols-2):
-+                reallocated_ra = PyMem_Realloc(
-+                    ra, sizeof(cnp.complex128_t)*no_of_cols*n*2)
-+                reallocated_ret = PyMem_Realloc(
-+                    ret, sizeof(cnp.complex128_t)*no_of_cols*n*2)
-+
-+                if reallocated_ra and reallocated_ret:
-+                    ra = reallocated_ra
-+                    ret = reallocated_ret
-+                    no_of_cols *= 2
-+                else:
-+                    raise MemoryError(
-+                        "'scipy.linalg.interpolative.idz_findrank()' failed to "
-+                        f"allocate the required memory,{no_of_cols*n*16} bytes "
-+                        "while trying to determine the rank (currently "
-+                        f"{krank}) of a LinearOperator with precision {eps}."
-+                    )
-+            krank += 1
-+            if (np.abs(y[krank-1]) < eps*enorm) or (krank >= min(m, n)):
-+                break
-+    finally:
-+        # Crashed or successfully ended up here
-+        # Discard Householder vectors
-+        PyMem_Free(ra)
-+        retarr = cnp.PyArray_EMPTY(2, [krank, n], cnp.NPY_COMPLEX128, 0)
-+        for k in range(krank):
-+            for kk in range(n):
-+                retarr[k, kk] = ret[k*n+kk]
-+        PyMem_Free(ret)
-+
-+    return krank, retarr
-+
-+
-+def idz_id2svd(
-+    cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] cols,
-+    cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms,
-+    cnp.ndarray[cnp.complex128_t, ndim=2] proj,
-+    ):
-+    cdef int m = cols.shape[0], krank = cols.shape[1]
-+    cdef int n = proj.shape[1] + krank, info, ci
-+    cdef cnp.ndarray[cnp.complex128_t, mode='fortran', ndim=2] C
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau1
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau2
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] UU
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
-+    cdef cnp.ndarray[cnp.complex128_t, ndim=2] V
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] VV
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] p
-+
-+    if krank > 0:
-+        UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_COMPLEX128, 0)
-+        VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_COMPLEX128, 0)
-+        p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_COMPLEX128, 0)
-+
-+        # idd_reconint
-+        for ci in range(krank):
-+            p[ci, perms[ci]] = 1.0
-+
-+        p[:, perms[krank:]] = proj[:, :]
-+        inds1, tau1 = idzr_qrpiv(cols, krank)
-+        # idz_rinqr and idz_rearr
-+        r = np.triu(cols[:krank, :])
-+        for ci in range(krank-1, -1, -1):
-+            r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
-+
-+        t = p.T.conj().copy()
-+        inds2, tau2 = idzr_qrpiv(t, krank)
-+        r2 = np.triu(t[:krank, :])
-+        for ci in range(krank-1, -1, -1):
-+            r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
-+
-+        r3 = r @ r2.T.conj()
-+        UU[:krank, :krank], S, V = la.svd(r3, full_matrices=False)
-+
-+        # Apply Q of col to U from the left
-+        # But do the adjoint dance for LAPACK via U.H @ Q.H
-+        np.conjugate(tau1, out=tau1)
-+        C = cols[:, :krank].conj().copy(order='F')
-+        zunm2r('R', 'C',
-+            &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
-+            &UU[0,0], &krank, &cols[0, 0], &info)
-+
-+        VV[:krank, :krank] = V[:, :].conj().T
-+
-+        # Apply Q of t to V from the left
-+        # But do the adjoint dance for LAPACK via V.H @ Q.H
-+        np.conjugate(tau2, out=tau2)
-+        C = t[:, :krank].conj().copy(order='F')
-+        zunm2r('R', 'C',
-+            &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
-+            &VV[0, 0], &krank, &cols[0, 0], &info)
-+
-+    return UU, S, VV
-+
-+
-+def idz_reconid(B, idx, proj):
-+    cdef int m = B.shape[0], krank = B.shape[1]
-+    cdef int n = len(idx)
-+    approx = np.zeros([m, n], dtype=np.complex128)
-+
-+    approx[:, idx[:krank]] = B
-+    approx[:, idx[krank:]] = B @ proj
-+
-+    return approx
-+
-+
-+def idz_snorm(A: LinearOperator, int its=20, rng=None):
-+    cdef int n = A.shape[1]
-+    cdef int j = 0, intone = 1
-+    cdef cnp.float64_t snorm = 0.0
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] v
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] u
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+
-+    v = rng.uniform(low=-1, high=1, size=(n, 2)).view(np.complex128).ravel()
-+    v /= dznrm2(&n, &v[0], &intone)
-+
-+    for j in range(its):
-+        u = A.matvec(v)
-+        v = A.rmatvec(u)
-+        snorm = dznrm2(&n, &v[0], &intone)
-+        if snorm > 0.0:
-+            v /= snorm
-+
-+        snorm = np.sqrt(snorm)
-+
-+    return snorm
-+
-+
-+def idzp_aid(cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] a: NDArray, eps: float,
-+             rng=None):
-+    krank, proj = idz_estrank(a, eps=eps, rng=rng)
-+    if krank != 0:
-+        proj = proj[:krank, :]
-+        return idzp_id(proj, eps=eps)
-+
-+    return idzp_id(a, eps=eps)
-+
-+
-+def idzp_asvd(cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] a, cnp.float64_t eps,
-+              rng=None):
-+    cdef int m = a.shape[0], n = a.shape[1]
-+    cdef int krank, info, ci
-+    cdef cnp.ndarray[cnp.complex128_t, mode='fortran', ndim=2] C
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau1
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau2
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] UU
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
-+    cdef cnp.ndarray[cnp.complex128_t, ndim=2] V
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] VV
-+    cdef cnp.ndarray[cnp.complex128_t, ndim=2] proj
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] perms
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] p
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] col
-+
-+    krank, perms, proj = idzp_aid(a.copy(), eps, rng)
-+
-+    if krank > 0:
-+        UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_COMPLEX128, 0)
-+        VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_COMPLEX128, 0)
-+        p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_COMPLEX128, 0)
-+        col = a[:, perms[:krank]].copy()
-+
-+        # idd_reconint
-+        for ci in range(krank):
-+            p[ci, perms[ci]] = 1.0
-+
-+        p[:, perms[krank:]] = proj[:, :]
-+        inds1, tau1 = idzr_qrpiv(col, krank)
-+        # idz_rinqr and idz_rearr
-+        r = np.triu(col[:krank, :])
-+        for ci in range(krank-1, -1, -1):
-+            r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
-+
-+        t = p.T.conj().copy()
-+        inds2, tau2 = idzr_qrpiv(t, krank)
-+        r2 = np.triu(t[:krank, :])
-+        for ci in range(krank-1, -1, -1):
-+            r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
-+
-+        r3 = r @ r2.T.conj()
-+        UU[:krank, :krank], S, V = la.svd(r3, full_matrices=False)
-+
-+        # Apply Q of col to U from the left
-+        # But do the adjoint dance for LAPACK via U.H @ Q.H
-+        np.conjugate(tau1, out=tau1)
-+        C = col[:, :krank].conj().copy(order='F')
-+        zunm2r('R', 'C',
-+            &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
-+            &UU[0,0], &krank, &a[0, 0], &info)
-+
-+        VV[:krank, :krank] = V[:, :].conj().T
-+
-+        # Apply Q of t to V from the left
-+        # But do the adjoint dance for LAPACK via V.H @ Q.H
-+        np.conjugate(tau2, out=tau2)
-+        C = t[:, :krank].conj().copy(order='F')
-+        zunm2r('R', 'C',
-+            &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
-+            &VV[0, 0], &krank, &a[0, 0], &info)
-+
-+    return UU, S, VV
-+
-+
-+def idzp_id(cnp.ndarray[cnp.complex128_t, mode="c", ndim=2] a, cnp.float64_t eps):
-+    cdef int n = a.shape[1], krank, tmp_int, p
-+    cdef double complex one = 1
-+    krank, _, inds = idzp_qrpiv(a, eps)
-+
-+    # Change pivots to permutation
-+    perms = cnp.PyArray_Arange(0, n, 1, cnp.NPY_INT64)
-+
-+    if krank > 0:
-+        for p in range(krank):
-+            # Apply pivots
-+            tmp_int = perms[p]
-+            perms[p] = perms[inds[p]]
-+            perms[inds[p]] = tmp_int
-+
-+    tmp_int = n - krank
-+    # SIDE,UPLO,TRANSA,DIAG,M,N,ALPHA,A,LDA,B,LDB
-+    ztrsm('R', 'L', 'N', 'N',
-+          &tmp_int, &krank, &one, &a[0, 0], &n, &a[0, krank], &n)
-+
-+    return krank, perms, a[:krank, krank:]
-+
-+
-+def idzp_qrpiv(cnp.ndarray[cnp.complex128_t, mode="c", ndim=2] a, cnp.float64_t eps):
-+    cdef int m = a.shape[0], n = a.shape[1]
-+    cdef cnp.ndarray col_norms = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
-+    cdef int k = 0, kpiv = 0, i = 0, tmp_int = 0, int_n = 0
-+    cdef double complex tmp_sca = 0.
-+    cdef cnp.ndarray taus = cnp.PyArray_ZEROS(1, [m], cnp.NPY_COMPLEX128, 0)
-+    cdef cnp.ndarray ind = cnp.PyArray_ZEROS(1, [n], cnp.NPY_INT64, 0)
-+    cdef double complex[::1] taus_v = taus
-+    cdef cnp.float64_t feps = 0.1e-16  # Smaller than np.finfo(np.float64).eps
-+    cdef cnp.float64_t ssmax, ssmaxin
-+    cdef int nupdate = 0
-+
-+    for i in range(n):
-+        col_norms[i] = dznrm2(&m, &a[0, i], &n)**2
-+
-+    kpiv = np.argmax(col_norms)
-+    ssmax = col_norms[kpiv]
-+    ssmaxin = ssmax
-+
-+    for k in range(min(m, n)):
-+
-+        # Pivoting
-+        ind[k] = kpiv
-+        # Swap columns a[:, k] and a[:, kpiv]
-+        a[:, [kpiv, k]] = a[:, [k, kpiv]]
-+
-+        # Swap col_norms[krank] and col_norms[kpiv]
-+        col_norms[[kpiv, k]] = col_norms[[k, kpiv]]
-+
-+        if k < m-1:
-+            # Compute the householder reflector for column k
-+            tmp_sca = a[k, k]
-+            # FIX: Convert these to F_INT
-+            tmp_int = (m - k)
-+            int_n = n
-+            zlarfgp(&tmp_int, &tmp_sca, &a[k+1, k], &int_n, &taus_v[k])
-+
-+            # Overwrite with 1. for easy matmul
-+            a[k, k] = 1.0
-+            if k < n-1:
-+                # Apply the householder reflector to the rest on the right.
-+                # Note! Tau returned by zlarfgp is complex valued and thus,
-+                # reflector is not Hermitian, hence the conjugates. See the
-+                # documentation of zlarfgp.
-+                a[k:, k+1:] -= np.outer(taus[k].conj()*a[k:, k],
-+                                        a[k:, k].conj() @ a[k:, k+1:]
-+                                        )
-+
-+            # Put back the beta in place
-+            a[k, k] = tmp_sca
-+            # Update the norms
-+            col_norms[k] = 0
-+            col_norms[k+1:] -= (a[k, k+1:] * a[k, k+1:].conj()).real
-+            ssmax = 0.0
-+            kpiv = k+1
-+
-+            if k < n-1:
-+                kpiv = np.argmax(col_norms[k+1:]) + (k + 1)
-+                ssmax = col_norms[kpiv]
-+
-+            if (((ssmax < 1000*feps*ssmaxin) and (nupdate == 0)) or
-+                    ((ssmax < ((1000*feps)**2)*ssmaxin) and (nupdate == 1))):
-+                nupdate += 1
-+                ssmax = 0
-+                kpiv = k+1
-+                if k < n-1:
-+                    for i in range(k+1, n):
-+                        tmp_int = m-k-1
-+                        col_norms[i] = dznrm2(&tmp_int, &a[k+1, i], &n)**2
-+                    kpiv = np.argmax(col_norms[k+1:]) + (k + 1)
-+                    ssmax = col_norms[kpiv]
-+        if (ssmax <= (eps**2)*ssmaxin):
-+            break
-+    # a is overwritten; return numerical rank and pivots
-+
-+    return k+1, taus, ind
-+
-+
-+def idzp_rid(A: LinearOperator, cnp.float64_t eps, rng=None):
-+    _, ret = idz_findrank(A, eps, rng=rng)
-+    return idzp_id(ret, eps=eps)
-+
-+
-+def idzp_rsvd(A: LinearOperator, cnp.float64_t eps, rng=None):
-+    cdef int n = A.shape[1]
-+    cdef int krank, j
-+    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms
-+    cdef cnp.ndarray[cnp.complex128_t, ndim=2] proj
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] col
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] x
-+
-+    krank, perms, proj = idzp_rid(A, eps, rng=rng)
-+
-+    if krank > 0:
-+        # idd_getcols
-+        col = cnp.PyArray_EMPTY(2, [n, krank], cnp.NPY_COMPLEX128, 0)
-+        x = cnp.PyArray_ZEROS(1, [n], cnp.NPY_COMPLEX128, 0)
-+
-+        for j in range(krank):
-+            x[perms[j]] = 1.
-+            col[:, j] = A.matvec(x)
-+            x[perms[j]] = 0.
-+
-+        return idz_id2svd(cols=col, perms=perms, proj=proj)
-+
-+    # TODO: figure out empty return
-+    return None
-+
-+
-+def idzp_svd(cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] a, cnp.float64_t eps):
-+    cdef int m = a.shape[0], krank, info
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] taus
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] UU
-+    cdef cnp.ndarray[cnp.complex128_t, ndim=2] V
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] r
-+    cdef cnp.ndarray[cnp.complex128_t, mode='fortran', ndim=2] C
-+    cdef cnp.ndarray[cnp.float64_t, ndim=1] S
-+
-+    # Get the pivoted QR
-+    krank, taus, inds = idzp_qrpiv(a, eps)
-+    UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_COMPLEX128, 0)
-+
-+    if krank > 0:
-+        r = np.triu(a[:krank, :])
-+
-+        for p in range(krank-1, -1, -1):
-+            r[:, [p, inds[p]]] = r[:, [inds[p], p]]
-+
-+        UU[:krank, :krank], S, V = la.svd(r, full_matrices=False)
-+        # Apply Q to U via zunm2r
-+        np.conjugate(taus, out=taus)
-+        # But do the adjoint dance for LAPACK via U.H @ Q.H; use a for scratch
-+        C = a[:, :krank].conj().copy(order='F')
-+        zunm2r('R', 'C',
-+               &krank, &m, &krank, &C[0, 0], &m, &taus[0],
-+               &UU[0,0], &krank, &a[0, 0], &info)
-+
-+    return UU, S, V
-+
-+
-+def idzr_aid(cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] a: NDArray, int krank,
-+             rng=None):
-+    cdef int m = a.shape[0], n2, L, nblock, nsteps = 3, mb
-+    cdef cnp.float64_t twopi = 2*np.pi, fact
-+    cdef double complex twopii = twopi*1.j
-+    cdef cnp.ndarray[cnp.npy_int64, mode='c', ndim=1] ind
-+    cdef cnp.ndarray[cnp.npy_int64, mode='c', ndim=1] subselect
-+    cdef cnp.ndarray[cnp.npy_float64, mode='c', ndim=1] dm1
-+    cdef cnp.ndarray[cnp.npy_float64, mode='c', ndim=1] dm2
-+    cdef cnp.ndarray[cnp.npy_float64, mode='c', ndim=3] albetas
-+    cdef cnp.ndarray[cnp.npy_float64, mode='c', ndim=2] rta
-+    cdef cnp.ndarray[cnp.npy_float64, mode='c', ndim=2] giv2x2
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+
-+    n2 = 0
-+    L = krank + 8
-+    if (L >= n2) or (L > m):
-+        inds, proj = idzr_id(a, krank)
-+        return inds, proj
-+
-+    n2 = idd_poweroftwo(m)
-+    # This part is the initialization that is done via idz_frmi
-+    # for a Subsampled Randomized Fourier Transfmrom (SRFT).
-+
-+    # Draw (nsteps x m x 4) array from [0, 2)*pi uniformly for
-+    # random points on complex unit circle and unitary rotations
-+    albetas = np.empty([nsteps, m, 4])
-+    albetas[:, :, 2:] = rng.uniform(low=0.0, high=2.0, size=[nsteps, m, 2])
-+    albetas[:, :, 2:] *= np.pi
-+    np.cos(albetas[:, :, 2], out=albetas[:, :, 0])
-+    np.sin(albetas[:, :, 2], out=albetas[:, :, 1])
-+    np.cos(albetas[:, :, 3], out=albetas[:, :, 2])
-+    np.sin(albetas[:, :, 3], out=albetas[:, :, 3])
-+
-+    # idd_random_transf
-+    rta = a.copy()
-+
-+    # Rotate and shuffle "a" nsteps-many times
-+    giv2x2 = np.array([[0., 0. ], [0., 0.]])
-+    for nstep in range(nsteps):
-+        # Multiply with a point on the unit circle
-+        rta *= albetas[nstep, :, 2:].view(np.complex128)
-+        # Rotate
-+        for row in range(m-1):
-+            alpha, beta = albetas[nstep, row, 0], albetas[nstep, row, 1]
-+            giv2x2[0, 0] = alpha
-+            giv2x2[0, 1] = beta
-+            giv2x2[1, 0] = -beta
-+            giv2x2[1, 1] = alpha
-+            np.matmul(giv2x2, rta[row:row+2, :], out=rta[row:row+2, :])
-+
-+        rta = rta[rng.permutation(m), :]
-+
-+    # idd_subselect pick randomly n2-many rows
-+    subselect = rng.choice(m, n2, replace=False)
-+    rta = rta[subselect, :]
-+    ind = rng.choice(n2, L, replace=False)
-+
-+    nblock = idd_ldiv(L, n2)
-+    mb = n2 // nblock
-+    fact = 1.0 / np.sqrt(n2)
-+
-+    # Create (L x mb) DFT matrix
-+    # wsave = np.empty([L, mb], dtype=np.complex128)
-+    dm1, dm2 = np.divmod(ind, mb, dtype=np.float64)
-+    dm1 /= n2
-+    dm1 += dm2 / mb
-+    wsave = np.outer(dm1, -twopii*np.arange(mb))
-+    np.exp(wsave, out=wsave)
-+    wsave *= fact
-+
-+    # Perform partial FFT to each nblock then swap first two axes for transposition
-+    # and subsample by ind // mb. This is basically a few options combined into one
-+    # First we view each column as (nblock x mb) then take fft of each mb-long chunk.
-+    # Then we transpose and multiply with DFT matrix and subselect.
-+    # See DOI:10.1016/j.acha.2007.12.002 - Section 3.3
-+
-+    # Original fortran code does this single column at a time. We do a bit of array
-+    # manipulation to do it in one go for all columns at once.
-+    F = np.swapaxes(
-+          fft(rta.reshape(nblock, mb, -1, order='F'), axis=0), 0, 1
-+          )[:, ind // mb, :]
-+    # Perform direct calculation with DFT matrix
-+    V = np.einsum('ij,jim->im', wsave, F)
-+
-+    return idzr_id(V, krank)
-+
-+
-+def idzr_asvd(cnp.ndarray[cnp.complex128_t, mode="c", ndim=2] a, int krank, rng=None):
-+    cdef int m = a.shape[0], n = a.shape[1]
-+    cdef int info, ci
-+    cdef cnp.ndarray[cnp.complex128_t, mode='fortran', ndim=2] C
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau1
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] tau2
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] UU
-+    cdef cnp.ndarray[cnp.float64_t, mode='c', ndim=1] S
-+    cdef cnp.ndarray[cnp.complex128_t, ndim=2] V
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] VV
-+    cdef cnp.ndarray[cnp.complex128_t, ndim=2] proj
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] perms
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds1
-+    cdef cnp.ndarray[cnp.npy_int64, ndim=1] inds2
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] p
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] col
-+    UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_COMPLEX128, 0)
-+    VV = cnp.PyArray_ZEROS(2, [n, krank], cnp.NPY_COMPLEX128, 0)
-+    p = cnp.PyArray_ZEROS(2, [krank, n], cnp.NPY_COMPLEX128, 0)
-+
-+    perms, proj = idzr_aid(a.copy(), krank=krank, rng=rng)
-+    col = a[:, perms[:krank]].copy()
-+
-+    # idd_reconint
-+    for ci in range(krank):
-+        p[ci, perms[ci]] = 1.0
-+
-+    p[:, perms[krank:]] = proj[:, :]
-+    inds1, tau1 = idzr_qrpiv(col, krank)
-+    # idz_rinqr and idz_rearr
-+    r = np.triu(col[:krank, :])
-+    for ci in range(krank-1, -1, -1):
-+        r[:, [ci, inds1[ci]]] = r[:,  [inds1[ci], ci]]
-+
-+    t = p.T.conj().copy()
-+    inds2, tau2 = idzr_qrpiv(t, krank)
-+    r2 = np.triu(t[:krank, :])
-+    for ci in range(krank-1, -1, -1):
-+        r2[:, [ci, inds2[ci]]] = r2[:,  [inds2[ci], ci]]
-+
-+    r3 = r @ r2.T.conj()
-+    UU[:krank, :krank], S, V = la.svd(r3, full_matrices=False)
-+
-+    # Apply Q of col to U from the left
-+    # But do the adjoint dance for LAPACK via U.H @ Q.H
-+    np.conjugate(tau1, out=tau1)
-+    C = col[:, :krank].conj().copy(order='F')
-+    zunm2r('R', 'C',
-+           &krank, &m, &krank, &C[0, 0], &m, &tau1[0],
-+           &UU[0,0], &krank, &a[0, 0], &info)
-+
-+    VV[:krank, :krank] = V[:, :].conj().T
-+
-+    # Apply Q of t to V from the left
-+    # But do the adjoint dance for LAPACK via V.H @ Q.H
-+    np.conjugate(tau2, out=tau2)
-+    C = t[:, :krank].conj().copy(order='F')
-+    zunm2r('R', 'C',
-+           &krank, &n, &krank, &C[0, 0], &n, &tau2[0],
-+           &VV[0, 0], &krank, &a[0, 0], &info)
-+
-+    return UU, S, VV
-+
-+
-+def idzr_id(cnp.ndarray[cnp.complex128_t, ndim=2] a, int krank):
-+    cdef int n = a.shape[1], tmp_int, p
-+    cdef double complex one = 1.0
-+    cdef cnp.ndarray[cnp.int64_t, ndim=1] inds
-+    cdef cnp.ndarray[cnp.int64_t, ndim=1] perms
-+
-+    inds, _ = idzr_qrpiv(a, krank)
-+    perms = cnp.PyArray_Arange(0, n, 1, cnp.NPY_INT64)
-+
-+    if krank > 0:
-+        for p in range(krank):
-+            # Apply pivots
-+            tmp_int = perms[p]
-+            perms[p] = perms[inds[p]]
-+            perms[inds[p]] = tmp_int
-+    tmp_int = n - krank
-+    # SIDE,UPLO,TRANSA,DIAG,M,N,ALPHA,A,LDA,B,LDB
-+    ztrsm('R', 'L', 'N', 'N',
-+          &tmp_int, &krank, &one, &a[0, 0], &n, &a[0, krank], &n)
-+
-+    return perms, a[:krank, krank:]
-+
-+
-+def idzr_qrpiv(cnp.ndarray[cnp.complex128_t, mode="c", ndim=2] a, int krank):
-+    cdef int m = a.shape[0], n = a.shape[1]
-+    cdef int loop = 0, loops, kpiv = 0, i = 0, tmp_int = 0
-+    cdef cnp.ndarray col_norms = cnp.PyArray_ZEROS(1, [n], cnp.NPY_FLOAT64, 0)
-+    cdef double complex tmp_sca = 0.
-+    cdef cnp.ndarray taus = cnp.PyArray_ZEROS(1, [m], cnp.NPY_COMPLEX128, 0)
-+    cdef cnp.ndarray ind = cnp.PyArray_ZEROS(1, [n], cnp.NPY_INT64, 0)
-+    cdef double complex[::1] taus_v = taus
-+    cdef cnp.float64_t feps = 0.1e-16  # Smaller than np.finfo(np.float64).eps
-+    cdef cnp.float64_t ssmax, ssmaxin
-+    cdef int nupdate = 0
-+
-+    loops = min(krank, min(m, n))
-+    for i in range(n):
-+        col_norms[i] = dznrm2(&m, &a[0, i], &n)**2
-+
-+    kpiv = np.argmax(col_norms)
-+    ssmax = col_norms[kpiv]
-+    ssmaxin = ssmax
-+
-+    for loop in range(loops):
-+
-+        ind[loop] = kpiv
-+        # Swap columns a[:, k] and a[:, kpiv]
-+        a[:, [kpiv, loop]] = a[:, [loop, kpiv]]
-+        # Swap col_norms[krank] and col_norms[kpiv]
-+        col_norms[[kpiv, loop]] = col_norms[[loop, kpiv]]
-+
-+        if loop < m-1:
-+            tmp_sca = a[loop, loop]
-+            # FIX: Convert these to F_INT
-+            tmp_int = (m - loop)
-+            zlarfgp(&tmp_int, &tmp_sca, &a[loop+1, loop], &n, &taus_v[loop])
-+
-+            # Overwrite with 1. for easy matmul
-+            a[loop, loop] = 1
-+            if loop < n-1:
-+                # Apply the householder reflector to the rest on the right
-+                a[loop:, loop+1:] -= np.outer(
-+                    np.conj(taus[loop])*a[loop:, loop],
-+                    a[loop:, loop].conj() @ a[loop:, loop+1:]
-+                    )
-+            # Put back the beta in place
-+            a[loop, loop] = tmp_sca
-+
-+            # Update the norms
-+            col_norms[loop] = 0
-+            col_norms[loop+1:] -= (a[loop, loop+1:]*a[loop, loop+1:].conj()).real
-+            ssmax = 0
-+            kpiv = loop+1
-+
-+            if loop < n-1:
-+                kpiv = np.argmax(col_norms[loop+1:]) + (loop + 1)
-+                ssmax = col_norms[kpiv]
-+            if (((ssmax < 1000*feps*ssmaxin) and (nupdate == 0)) or
-+                    ((ssmax < ((1000*feps)**2)*ssmaxin) and (nupdate == 1))):
-+                nupdate += 1
-+                ssmax = 0
-+                kpiv = loop+1
-+
-+                if loop < n-1:
-+                    for i in range(loop+1, n):
-+                        tmp_int = m-loop-1
-+                        col_norms[i] = dznrm2(&tmp_int, &a[loop+1, i], &n)**2
-+                    kpiv = np.argmax(col_norms[loop+1:]) + (loop + 1)
-+                    ssmax = col_norms[kpiv]
-+
-+    return ind, taus
-+
-+
-+def idzr_rid(A: LinearOperator, int krank, rng=None):
-+    cdef int m = A.shape[0], n = A.shape[1], k = 0
-+    cdef int L = min(krank+2, min(m, n))
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] r
-+
-+    if not rng:
-+        rng = np.random.default_rng()
-+
-+    r = cnp.PyArray_EMPTY(2, [L, n], cnp.NPY_COMPLEX128, 0)
-+    for k in range(L):
-+        r[k, :] = A.rmatvec(rng.uniform(size=(m,2)).view(np.complex128).ravel())
-+
-+    return idzr_id(a=r.conj(), krank=krank)
-+
-+
-+def idzr_rsvd(A: LinearOperator, int krank, rng=None):
-+    cdef int n = A.shape[1], j
-+    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] perms
-+    cdef cnp.ndarray[cnp.complex128_t, ndim=2] proj
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] col
-+
-+    perms, proj = idzr_rid(A, krank, rng)
-+    # idd_getcols
-+    col = cnp.PyArray_EMPTY(2, [n, krank], cnp.NPY_COMPLEX128, 0)
-+    x = cnp.PyArray_ZEROS(1, [n], cnp.NPY_COMPLEX128, 0)
-+    for j in range(krank):
-+        x[perms[j]] = 1.
-+        col[:, j] = A.matvec(x)
-+        x[perms[j]] = 0.
-+
-+    return idz_id2svd(cols=col, perms=perms, proj=proj)
-+
-+
-+def idzr_svd(cnp.ndarray[cnp.complex128_t, mode="c", ndim=2] a, int krank):
-+    cdef int m = a.shape[0], n = a.shape[1], info = 0
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=1] taus
-+    cdef cnp.ndarray[cnp.int64_t, mode='c', ndim=1] inds
-+    cdef cnp.ndarray[cnp.complex128_t, mode='c', ndim=2] UU
-+    cdef cnp.ndarray[cnp.complex128_t, mode='fortran', ndim=2] C
-+    UU = cnp.PyArray_ZEROS(2, [m, krank], cnp.NPY_COMPLEX128, 0)
-+
-+    krank = min(krank, min(m, n))
-+    # Get the pivoted QR
-+    inds, taus = idzr_qrpiv(a, krank)
-+    r = np.triu(a[:krank, :])
-+    # Apply pivots in reverse
-+    for p in range(krank-1, -1, -1):
-+        r[:, [p, inds[p]]] = r[:, [inds[p], p]]
-+
-+    # JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO
-+    # zgesvd()
-+    UU[:krank, :krank], S, V = la.svd(r, full_matrices=False)
-+
-+    # Apply Q to U via zunm2r
-+    np.conjugate(taus, out=taus)
-+    # But do the adjoint dance for LAPACK via U.H @ Q.H; use a for scratch
-+    C = a[:, :krank].conj().copy(order='F')
-+    zunm2r('R', 'C',
-+           &krank, &m, &krank, &C[0, 0], &m, &taus[0],
-+           &UU[0,0], &krank, &a[0, 0], &info)
-+
-+    return UU, S, V
-diff --git a/scipy/linalg/_interpolative_backend.py b/scipy/linalg/_interpolative_backend.py
-deleted file mode 100644
-index 7835314f7..000000000
---- a/scipy/linalg/_interpolative_backend.py
-+++ /dev/null
-@@ -1,1681 +0,0 @@
--#******************************************************************************
--#   Copyright (C) 2013 Kenneth L. Ho
--#
--#   Redistribution and use in source and binary forms, with or without
--#   modification, are permitted provided that the following conditions are met:
--#
--#   Redistributions of source code must retain the above copyright notice, this
--#   list of conditions and the following disclaimer. Redistributions in binary
--#   form must reproduce the above copyright notice, this list of conditions and
--#   the following disclaimer in the documentation and/or other materials
--#   provided with the distribution.
--#
--#   None of the names of the copyright holders may be used to endorse or
--#   promote products derived from this software without specific prior written
--#   permission.
--#
--#   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
--#   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
--#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
--#   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
--#   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
--#   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
--#   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
--#   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
--#   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
--#   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
--#   POSSIBILITY OF SUCH DAMAGE.
--#******************************************************************************
--
--"""
--Direct wrappers for Fortran `id_dist` backend.
--"""
--
--import scipy.linalg._interpolative as _id
--import numpy as np
--
--_RETCODE_ERROR = RuntimeError("nonzero return code")
--
--
--def _asfortranarray_copy(A):
--    """
--    Same as np.asfortranarray, but ensure a copy
--    """
--    A = np.asarray(A)
--    if A.flags.f_contiguous:
--        A = A.copy(order="F")
--    else:
--        A = np.asfortranarray(A)
--    return A
--
--
--#------------------------------------------------------------------------------
--# id_rand.f
--#------------------------------------------------------------------------------
--
--def id_srand(n):
--    """
--    Generate standard uniform pseudorandom numbers via a very efficient lagged
--    Fibonacci method.
--
--    :param n:
--        Number of pseudorandom numbers to generate.
--    :type n: int
--
--    :return:
--        Pseudorandom numbers.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.id_srand(n)
--
--
--def id_srandi(t):
--    """
--    Initialize seed values for :func:`id_srand` (any appropriately random
--    numbers will do).
--
--    :param t:
--        Array of 55 seed values.
--    :type t: :class:`numpy.ndarray`
--    """
--    t = np.asfortranarray(t)
--    _id.id_srandi(t)
--
--
--def id_srando():
--    """
--    Reset seed values to their original values.
--    """
--    _id.id_srando()
--
--
--#------------------------------------------------------------------------------
--# idd_frm.f
--#------------------------------------------------------------------------------
--
--def idd_frm(n, w, x):
--    """
--    Transform real vector via a composition of Rokhlin's random transform,
--    random subselection, and an FFT.
--
--    In contrast to :func:`idd_sfrm`, this routine works best when the length of
--    the transformed vector is the power-of-two integer output by
--    :func:`idd_frmi`, or when the length is not specified but instead
--    determined a posteriori from the output. The returned transformed vector is
--    randomly permuted.
--
--    :param n:
--        Greatest power-of-two integer satisfying `n <= x.size` as obtained from
--        :func:`idd_frmi`; `n` is also the length of the output vector.
--    :type n: int
--    :param w:
--        Initialization array constructed by :func:`idd_frmi`.
--    :type w: :class:`numpy.ndarray`
--    :param x:
--        Vector to be transformed.
--    :type x: :class:`numpy.ndarray`
--
--    :return:
--        Transformed vector.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idd_frm(n, w, x)
--
--
--def idd_sfrm(l, n, w, x):
--    """
--    Transform real vector via a composition of Rokhlin's random transform,
--    random subselection, and an FFT.
--
--    In contrast to :func:`idd_frm`, this routine works best when the length of
--    the transformed vector is known a priori.
--
--    :param l:
--        Length of transformed vector, satisfying `l <= n`.
--    :type l: int
--    :param n:
--        Greatest power-of-two integer satisfying `n <= x.size` as obtained from
--        :func:`idd_sfrmi`.
--    :type n: int
--    :param w:
--        Initialization array constructed by :func:`idd_sfrmi`.
--    :type w: :class:`numpy.ndarray`
--    :param x:
--        Vector to be transformed.
--    :type x: :class:`numpy.ndarray`
--
--    :return:
--        Transformed vector.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idd_sfrm(l, n, w, x)
--
--
--def idd_frmi(m):
--    """
--    Initialize data for :func:`idd_frm`.
--
--    :param m:
--        Length of vector to be transformed.
--    :type m: int
--
--    :return:
--        Greatest power-of-two integer `n` satisfying `n <= m`.
--    :rtype: int
--    :return:
--        Initialization array to be used by :func:`idd_frm`.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idd_frmi(m)
--
--
--def idd_sfrmi(l, m):
--    """
--    Initialize data for :func:`idd_sfrm`.
--
--    :param l:
--        Length of output transformed vector.
--    :type l: int
--    :param m:
--        Length of the vector to be transformed.
--    :type m: int
--
--    :return:
--        Greatest power-of-two integer `n` satisfying `n <= m`.
--    :rtype: int
--    :return:
--        Initialization array to be used by :func:`idd_sfrm`.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idd_sfrmi(l, m)
--
--
--#------------------------------------------------------------------------------
--# idd_id.f
--#------------------------------------------------------------------------------
--
--def iddp_id(eps, A):
--    """
--    Compute ID of a real matrix to a specified relative precision.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--
--    :return:
--        Rank of ID.
--    :rtype: int
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = _asfortranarray_copy(A)
--    k, idx, rnorms = _id.iddp_id(eps, A)
--    n = A.shape[1]
--    proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
--    return k, idx, proj
--
--
--def iddr_id(A, k):
--    """
--    Compute ID of a real matrix to a specified rank.
--
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--    :param k:
--        Rank of ID.
--    :type k: int
--
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = _asfortranarray_copy(A)
--    idx, rnorms = _id.iddr_id(A, k)
--    n = A.shape[1]
--    proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
--    return idx, proj
--
--
--def idd_reconid(B, idx, proj):
--    """
--    Reconstruct matrix from real ID.
--
--    :param B:
--        Skeleton matrix.
--    :type B: :class:`numpy.ndarray`
--    :param idx:
--        Column index array.
--    :type idx: :class:`numpy.ndarray`
--    :param proj:
--        Interpolation coefficients.
--    :type proj: :class:`numpy.ndarray`
--
--    :return:
--        Reconstructed matrix.
--    :rtype: :class:`numpy.ndarray`
--    """
--    B = np.asfortranarray(B)
--    if proj.size > 0:
--        return _id.idd_reconid(B, idx, proj)
--    else:
--        return B[:, np.argsort(idx)]
--
--
--def idd_reconint(idx, proj):
--    """
--    Reconstruct interpolation matrix from real ID.
--
--    :param idx:
--        Column index array.
--    :type idx: :class:`numpy.ndarray`
--    :param proj:
--        Interpolation coefficients.
--    :type proj: :class:`numpy.ndarray`
--
--    :return:
--        Interpolation matrix.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idd_reconint(idx, proj)
--
--
--def idd_copycols(A, k, idx):
--    """
--    Reconstruct skeleton matrix from real ID.
--
--    :param A:
--        Original matrix.
--    :type A: :class:`numpy.ndarray`
--    :param k:
--        Rank of ID.
--    :type k: int
--    :param idx:
--        Column index array.
--    :type idx: :class:`numpy.ndarray`
--
--    :return:
--        Skeleton matrix.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    return _id.idd_copycols(A, k, idx)
--
--
--#------------------------------------------------------------------------------
--# idd_id2svd.f
--#------------------------------------------------------------------------------
--
--def idd_id2svd(B, idx, proj):
--    """
--    Convert real ID to SVD.
--
--    :param B:
--        Skeleton matrix.
--    :type B: :class:`numpy.ndarray`
--    :param idx:
--        Column index array.
--    :type idx: :class:`numpy.ndarray`
--    :param proj:
--        Interpolation coefficients.
--    :type proj: :class:`numpy.ndarray`
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    B = np.asfortranarray(B)
--    U, V, S, ier = _id.idd_id2svd(B, idx, proj)
--    if ier:
--        raise _RETCODE_ERROR
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# idd_snorm.f
--#------------------------------------------------------------------------------
--
--def idd_snorm(m, n, matvect, matvec, its=20):
--    """
--    Estimate spectral norm of a real matrix by the randomized power method.
--
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matvect:
--        Function to apply the matrix transpose to a vector, with call signature
--        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvect: function
--    :param matvec:
--        Function to apply the matrix to a vector, with call signature
--        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvec: function
--    :param its:
--        Number of power method iterations.
--    :type its: int
--
--    :return:
--        Spectral norm estimate.
--    :rtype: float
--    """
--    snorm, v = _id.idd_snorm(m, n, matvect, matvec, its)
--    return snorm
--
--
--def idd_diffsnorm(m, n, matvect, matvect2, matvec, matvec2, its=20):
--    """
--    Estimate spectral norm of the difference of two real matrices by the
--    randomized power method.
--
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matvect:
--        Function to apply the transpose of the first matrix to a vector, with
--        call signature `y = matvect(x)`, where `x` and `y` are the input and
--        output vectors, respectively.
--    :type matvect: function
--    :param matvect2:
--        Function to apply the transpose of the second matrix to a vector, with
--        call signature `y = matvect2(x)`, where `x` and `y` are the input and
--        output vectors, respectively.
--    :type matvect2: function
--    :param matvec:
--        Function to apply the first matrix to a vector, with call signature
--        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvec: function
--    :param matvec2:
--        Function to apply the second matrix to a vector, with call signature
--        `y = matvec2(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvec2: function
--    :param its:
--        Number of power method iterations.
--    :type its: int
--
--    :return:
--        Spectral norm estimate of matrix difference.
--    :rtype: float
--    """
--    return _id.idd_diffsnorm(m, n, matvect, matvect2, matvec, matvec2, its)
--
--
--#------------------------------------------------------------------------------
--# idd_svd.f
--#------------------------------------------------------------------------------
--
--def iddr_svd(A, k):
--    """
--    Compute SVD of a real matrix to a specified rank.
--
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--    :param k:
--        Rank of SVD.
--    :type k: int
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    U, V, S, ier = _id.iddr_svd(A, k)
--    if ier:
--        raise _RETCODE_ERROR
--    return U, V, S
--
--
--def iddp_svd(eps, A):
--    """
--    Compute SVD of a real matrix to a specified relative precision.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    k, iU, iV, iS, w, ier = _id.iddp_svd(eps, A)
--    if ier:
--        raise _RETCODE_ERROR
--    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
--    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
--    S = w[iS-1:iS+k-1]
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# iddp_aid.f
--#------------------------------------------------------------------------------
--
--def iddp_aid(eps, A):
--    """
--    Compute ID of a real matrix to a specified relative precision using random
--    sampling.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--
--    :return:
--        Rank of ID.
--    :rtype: int
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    n2, w = idd_frmi(m)
--    proj = np.empty(n*(2*n2 + 1) + n2 + 1, order='F')
--    k, idx, proj = _id.iddp_aid(eps, A, w, proj)
--    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
--    return k, idx, proj
--
--
--def idd_estrank(eps, A):
--    """
--    Estimate rank of a real matrix to a specified relative precision using
--    random sampling.
--
--    The output rank is typically about 8 higher than the actual rank.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--
--    :return:
--        Rank estimate.
--    :rtype: int
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    n2, w = idd_frmi(m)
--    ra = np.empty(n*n2 + (n + 1)*(n2 + 1), order='F')
--    k, ra = _id.idd_estrank(eps, A, w, ra)
--    return k
--
--
--#------------------------------------------------------------------------------
--# iddp_asvd.f
--#------------------------------------------------------------------------------
--
--def iddp_asvd(eps, A):
--    """
--    Compute SVD of a real matrix to a specified relative precision using random
--    sampling.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    n2, winit = _id.idd_frmi(m)
--    w = np.empty(
--        max((min(m, n) + 1)*(3*m + 5*n + 1) + 25*min(m, n)**2,
--            (2*n + 1)*(n2 + 1)),
--        order='F')
--    k, iU, iV, iS, w, ier = _id.iddp_asvd(eps, A, winit, w)
--    if ier:
--        raise _RETCODE_ERROR
--    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
--    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
--    S = w[iS-1:iS+k-1]
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# iddp_rid.f
--#------------------------------------------------------------------------------
--
--def iddp_rid(eps, m, n, matvect):
--    """
--    Compute ID of a real matrix to a specified relative precision using random
--    matrix-vector multiplication.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matvect:
--        Function to apply the matrix transpose to a vector, with call signature
--        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvect: function
--
--    :return:
--        Rank of ID.
--    :rtype: int
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    proj = np.empty(m + 1 + 2*n*(min(m, n) + 1), order='F')
--    k, idx, proj, ier = _id.iddp_rid(eps, m, n, matvect, proj)
--    if ier != 0:
--        raise _RETCODE_ERROR
--    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
--    return k, idx, proj
--
--
--def idd_findrank(eps, m, n, matvect):
--    """
--    Estimate rank of a real matrix to a specified relative precision using
--    random matrix-vector multiplication.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matvect:
--        Function to apply the matrix transpose to a vector, with call signature
--        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvect: function
--
--    :return:
--        Rank estimate.
--    :rtype: int
--    """
--    k, ra, ier = _id.idd_findrank(eps, m, n, matvect)
--    if ier:
--        raise _RETCODE_ERROR
--    return k
--
--
--#------------------------------------------------------------------------------
--# iddp_rsvd.f
--#------------------------------------------------------------------------------
--
--def iddp_rsvd(eps, m, n, matvect, matvec):
--    """
--    Compute SVD of a real matrix to a specified relative precision using random
--    matrix-vector multiplication.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matvect:
--        Function to apply the matrix transpose to a vector, with call signature
--        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvect: function
--    :param matvec:
--        Function to apply the matrix to a vector, with call signature
--        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvec: function
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    k, iU, iV, iS, w, ier = _id.iddp_rsvd(eps, m, n, matvect, matvec)
--    if ier:
--        raise _RETCODE_ERROR
--    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
--    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
--    S = w[iS-1:iS+k-1]
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# iddr_aid.f
--#------------------------------------------------------------------------------
--
--def iddr_aid(A, k):
--    """
--    Compute ID of a real matrix to a specified rank using random sampling.
--
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--    :param k:
--        Rank of ID.
--    :type k: int
--
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    w = iddr_aidi(m, n, k)
--    idx, proj = _id.iddr_aid(A, k, w)
--    if k == n:
--        proj = np.empty((k, n-k), dtype='float64', order='F')
--    else:
--        proj = proj.reshape((k, n-k), order='F')
--    return idx, proj
--
--
--def iddr_aidi(m, n, k):
--    """
--    Initialize array for :func:`iddr_aid`.
--
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param k:
--        Rank of ID.
--    :type k: int
--
--    :return:
--        Initialization array to be used by :func:`iddr_aid`.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.iddr_aidi(m, n, k)
--
--
--#------------------------------------------------------------------------------
--# iddr_asvd.f
--#------------------------------------------------------------------------------
--
--def iddr_asvd(A, k):
--    """
--    Compute SVD of a real matrix to a specified rank using random sampling.
--
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--    :param k:
--        Rank of SVD.
--    :type k: int
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    w = np.empty((2*k + 28)*m + (6*k + 21)*n + 25*k**2 + 100, order='F')
--    w_ = iddr_aidi(m, n, k)
--    w[:w_.size] = w_
--    U, V, S, ier = _id.iddr_asvd(A, k, w)
--    if ier != 0:
--        raise _RETCODE_ERROR
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# iddr_rid.f
--#------------------------------------------------------------------------------
--
--def iddr_rid(m, n, matvect, k):
--    """
--    Compute ID of a real matrix to a specified rank using random matrix-vector
--    multiplication.
--
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matvect:
--        Function to apply the matrix transpose to a vector, with call signature
--        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvect: function
--    :param k:
--        Rank of ID.
--    :type k: int
--
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    idx, proj = _id.iddr_rid(m, n, matvect, k)
--    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
--    return idx, proj
--
--
--#------------------------------------------------------------------------------
--# iddr_rsvd.f
--#------------------------------------------------------------------------------
--
--def iddr_rsvd(m, n, matvect, matvec, k):
--    """
--    Compute SVD of a real matrix to a specified rank using random matrix-vector
--    multiplication.
--
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matvect:
--        Function to apply the matrix transpose to a vector, with call signature
--        `y = matvect(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvect: function
--    :param matvec:
--        Function to apply the matrix to a vector, with call signature
--        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvec: function
--    :param k:
--        Rank of SVD.
--    :type k: int
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    U, V, S, ier = _id.iddr_rsvd(m, n, matvect, matvec, k)
--    if ier != 0:
--        raise _RETCODE_ERROR
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# idz_frm.f
--#------------------------------------------------------------------------------
--
--def idz_frm(n, w, x):
--    """
--    Transform complex vector via a composition of Rokhlin's random transform,
--    random subselection, and an FFT.
--
--    In contrast to :func:`idz_sfrm`, this routine works best when the length of
--    the transformed vector is the power-of-two integer output by
--    :func:`idz_frmi`, or when the length is not specified but instead
--    determined a posteriori from the output. The returned transformed vector is
--    randomly permuted.
--
--    :param n:
--        Greatest power-of-two integer satisfying `n <= x.size` as obtained from
--        :func:`idz_frmi`; `n` is also the length of the output vector.
--    :type n: int
--    :param w:
--        Initialization array constructed by :func:`idz_frmi`.
--    :type w: :class:`numpy.ndarray`
--    :param x:
--        Vector to be transformed.
--    :type x: :class:`numpy.ndarray`
--
--    :return:
--        Transformed vector.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idz_frm(n, w, x)
--
--
--def idz_sfrm(l, n, w, x):
--    """
--    Transform complex vector via a composition of Rokhlin's random transform,
--    random subselection, and an FFT.
--
--    In contrast to :func:`idz_frm`, this routine works best when the length of
--    the transformed vector is known a priori.
--
--    :param l:
--        Length of transformed vector, satisfying `l <= n`.
--    :type l: int
--    :param n:
--        Greatest power-of-two integer satisfying `n <= x.size` as obtained from
--        :func:`idz_sfrmi`.
--    :type n: int
--    :param w:
--        Initialization array constructed by :func:`idd_sfrmi`.
--    :type w: :class:`numpy.ndarray`
--    :param x:
--        Vector to be transformed.
--    :type x: :class:`numpy.ndarray`
--
--    :return:
--        Transformed vector.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idz_sfrm(l, n, w, x)
--
--
--def idz_frmi(m):
--    """
--    Initialize data for :func:`idz_frm`.
--
--    :param m:
--        Length of vector to be transformed.
--    :type m: int
--
--    :return:
--        Greatest power-of-two integer `n` satisfying `n <= m`.
--    :rtype: int
--    :return:
--        Initialization array to be used by :func:`idz_frm`.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idz_frmi(m)
--
--
--def idz_sfrmi(l, m):
--    """
--    Initialize data for :func:`idz_sfrm`.
--
--    :param l:
--        Length of output transformed vector.
--    :type l: int
--    :param m:
--        Length of the vector to be transformed.
--    :type m: int
--
--    :return:
--        Greatest power-of-two integer `n` satisfying `n <= m`.
--    :rtype: int
--    :return:
--        Initialization array to be used by :func:`idz_sfrm`.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idz_sfrmi(l, m)
--
--
--#------------------------------------------------------------------------------
--# idz_id.f
--#------------------------------------------------------------------------------
--
--def idzp_id(eps, A):
--    """
--    Compute ID of a complex matrix to a specified relative precision.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--
--    :return:
--        Rank of ID.
--    :rtype: int
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = _asfortranarray_copy(A)
--    k, idx, rnorms = _id.idzp_id(eps, A)
--    n = A.shape[1]
--    proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
--    return k, idx, proj
--
--
--def idzr_id(A, k):
--    """
--    Compute ID of a complex matrix to a specified rank.
--
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--    :param k:
--        Rank of ID.
--    :type k: int
--
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = _asfortranarray_copy(A)
--    idx, rnorms = _id.idzr_id(A, k)
--    n = A.shape[1]
--    proj = A.T.ravel()[:k*(n-k)].reshape((k, n-k), order='F')
--    return idx, proj
--
--
--def idz_reconid(B, idx, proj):
--    """
--    Reconstruct matrix from complex ID.
--
--    :param B:
--        Skeleton matrix.
--    :type B: :class:`numpy.ndarray`
--    :param idx:
--        Column index array.
--    :type idx: :class:`numpy.ndarray`
--    :param proj:
--        Interpolation coefficients.
--    :type proj: :class:`numpy.ndarray`
--
--    :return:
--        Reconstructed matrix.
--    :rtype: :class:`numpy.ndarray`
--    """
--    B = np.asfortranarray(B)
--    if proj.size > 0:
--        return _id.idz_reconid(B, idx, proj)
--    else:
--        return B[:, np.argsort(idx)]
--
--
--def idz_reconint(idx, proj):
--    """
--    Reconstruct interpolation matrix from complex ID.
--
--    :param idx:
--        Column index array.
--    :type idx: :class:`numpy.ndarray`
--    :param proj:
--        Interpolation coefficients.
--    :type proj: :class:`numpy.ndarray`
--
--    :return:
--        Interpolation matrix.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idz_reconint(idx, proj)
--
--
--def idz_copycols(A, k, idx):
--    """
--    Reconstruct skeleton matrix from complex ID.
--
--    :param A:
--        Original matrix.
--    :type A: :class:`numpy.ndarray`
--    :param k:
--        Rank of ID.
--    :type k: int
--    :param idx:
--        Column index array.
--    :type idx: :class:`numpy.ndarray`
--
--    :return:
--        Skeleton matrix.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    return _id.idz_copycols(A, k, idx)
--
--
--#------------------------------------------------------------------------------
--# idz_id2svd.f
--#------------------------------------------------------------------------------
--
--def idz_id2svd(B, idx, proj):
--    """
--    Convert complex ID to SVD.
--
--    :param B:
--        Skeleton matrix.
--    :type B: :class:`numpy.ndarray`
--    :param idx:
--        Column index array.
--    :type idx: :class:`numpy.ndarray`
--    :param proj:
--        Interpolation coefficients.
--    :type proj: :class:`numpy.ndarray`
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    B = np.asfortranarray(B)
--    U, V, S, ier = _id.idz_id2svd(B, idx, proj)
--    if ier:
--        raise _RETCODE_ERROR
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# idz_snorm.f
--#------------------------------------------------------------------------------
--
--def idz_snorm(m, n, matveca, matvec, its=20):
--    """
--    Estimate spectral norm of a complex matrix by the randomized power method.
--
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matveca:
--        Function to apply the matrix adjoint to a vector, with call signature
--        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matveca: function
--    :param matvec:
--        Function to apply the matrix to a vector, with call signature
--        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvec: function
--    :param its:
--        Number of power method iterations.
--    :type its: int
--
--    :return:
--        Spectral norm estimate.
--    :rtype: float
--    """
--    snorm, v = _id.idz_snorm(m, n, matveca, matvec, its)
--    return snorm
--
--
--def idz_diffsnorm(m, n, matveca, matveca2, matvec, matvec2, its=20):
--    """
--    Estimate spectral norm of the difference of two complex matrices by the
--    randomized power method.
--
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matveca:
--        Function to apply the adjoint of the first matrix to a vector, with
--        call signature `y = matveca(x)`, where `x` and `y` are the input and
--        output vectors, respectively.
--    :type matveca: function
--    :param matveca2:
--        Function to apply the adjoint of the second matrix to a vector, with
--        call signature `y = matveca2(x)`, where `x` and `y` are the input and
--        output vectors, respectively.
--    :type matveca2: function
--    :param matvec:
--        Function to apply the first matrix to a vector, with call signature
--        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvec: function
--    :param matvec2:
--        Function to apply the second matrix to a vector, with call signature
--        `y = matvec2(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvec2: function
--    :param its:
--        Number of power method iterations.
--    :type its: int
--
--    :return:
--        Spectral norm estimate of matrix difference.
--    :rtype: float
--    """
--    return _id.idz_diffsnorm(m, n, matveca, matveca2, matvec, matvec2, its)
--
--
--#------------------------------------------------------------------------------
--# idz_svd.f
--#------------------------------------------------------------------------------
--
--def idzr_svd(A, k):
--    """
--    Compute SVD of a complex matrix to a specified rank.
--
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--    :param k:
--        Rank of SVD.
--    :type k: int
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    U, V, S, ier = _id.idzr_svd(A, k)
--    if ier:
--        raise _RETCODE_ERROR
--    return U, V, S
--
--
--def idzp_svd(eps, A):
--    """
--    Compute SVD of a complex matrix to a specified relative precision.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    k, iU, iV, iS, w, ier = _id.idzp_svd(eps, A)
--    if ier:
--        raise _RETCODE_ERROR
--    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
--    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
--    S = w[iS-1:iS+k-1]
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# idzp_aid.f
--#------------------------------------------------------------------------------
--
--def idzp_aid(eps, A):
--    """
--    Compute ID of a complex matrix to a specified relative precision using
--    random sampling.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--
--    :return:
--        Rank of ID.
--    :rtype: int
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    n2, w = idz_frmi(m)
--    proj = np.empty(n*(2*n2 + 1) + n2 + 1, dtype='complex128', order='F')
--    k, idx, proj = _id.idzp_aid(eps, A, w, proj)
--    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
--    return k, idx, proj
--
--
--def idz_estrank(eps, A):
--    """
--    Estimate rank of a complex matrix to a specified relative precision using
--    random sampling.
--
--    The output rank is typically about 8 higher than the actual rank.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--
--    :return:
--        Rank estimate.
--    :rtype: int
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    n2, w = idz_frmi(m)
--    ra = np.empty(n*n2 + (n + 1)*(n2 + 1), dtype='complex128', order='F')
--    k, ra = _id.idz_estrank(eps, A, w, ra)
--    return k
--
--
--#------------------------------------------------------------------------------
--# idzp_asvd.f
--#------------------------------------------------------------------------------
--
--def idzp_asvd(eps, A):
--    """
--    Compute SVD of a complex matrix to a specified relative precision using
--    random sampling.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    n2, winit = _id.idz_frmi(m)
--    w = np.empty(
--        max((min(m, n) + 1)*(3*m + 5*n + 11) + 8*min(m, n)**2,
--            (2*n + 1)*(n2 + 1)),
--        dtype=np.complex128, order='F')
--    k, iU, iV, iS, w, ier = _id.idzp_asvd(eps, A, winit, w)
--    if ier:
--        raise _RETCODE_ERROR
--    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
--    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
--    S = w[iS-1:iS+k-1]
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# idzp_rid.f
--#------------------------------------------------------------------------------
--
--def idzp_rid(eps, m, n, matveca):
--    """
--    Compute ID of a complex matrix to a specified relative precision using
--    random matrix-vector multiplication.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matveca:
--        Function to apply the matrix adjoint to a vector, with call signature
--        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matveca: function
--
--    :return:
--        Rank of ID.
--    :rtype: int
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    proj = np.empty(
--        m + 1 + 2*n*(min(m, n) + 1),
--        dtype=np.complex128, order='F')
--    k, idx, proj, ier = _id.idzp_rid(eps, m, n, matveca, proj)
--    if ier:
--        raise _RETCODE_ERROR
--    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
--    return k, idx, proj
--
--
--def idz_findrank(eps, m, n, matveca):
--    """
--    Estimate rank of a complex matrix to a specified relative precision using
--    random matrix-vector multiplication.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matveca:
--        Function to apply the matrix adjoint to a vector, with call signature
--        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matveca: function
--
--    :return:
--        Rank estimate.
--    :rtype: int
--    """
--    k, ra, ier = _id.idz_findrank(eps, m, n, matveca)
--    if ier:
--        raise _RETCODE_ERROR
--    return k
--
--
--#------------------------------------------------------------------------------
--# idzp_rsvd.f
--#------------------------------------------------------------------------------
--
--def idzp_rsvd(eps, m, n, matveca, matvec):
--    """
--    Compute SVD of a complex matrix to a specified relative precision using
--    random matrix-vector multiplication.
--
--    :param eps:
--        Relative precision.
--    :type eps: float
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matveca:
--        Function to apply the matrix adjoint to a vector, with call signature
--        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matveca: function
--    :param matvec:
--        Function to apply the matrix to a vector, with call signature
--        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvec: function
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    k, iU, iV, iS, w, ier = _id.idzp_rsvd(eps, m, n, matveca, matvec)
--    if ier:
--        raise _RETCODE_ERROR
--    U = w[iU-1:iU+m*k-1].reshape((m, k), order='F')
--    V = w[iV-1:iV+n*k-1].reshape((n, k), order='F')
--    S = w[iS-1:iS+k-1]
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# idzr_aid.f
--#------------------------------------------------------------------------------
--
--def idzr_aid(A, k):
--    """
--    Compute ID of a complex matrix to a specified rank using random sampling.
--
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--    :param k:
--        Rank of ID.
--    :type k: int
--
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    w = idzr_aidi(m, n, k)
--    idx, proj = _id.idzr_aid(A, k, w)
--    if k == n:
--        proj = np.empty((k, n-k), dtype='complex128', order='F')
--    else:
--        proj = proj.reshape((k, n-k), order='F')
--    return idx, proj
--
--
--def idzr_aidi(m, n, k):
--    """
--    Initialize array for :func:`idzr_aid`.
--
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param k:
--        Rank of ID.
--    :type k: int
--
--    :return:
--        Initialization array to be used by :func:`idzr_aid`.
--    :rtype: :class:`numpy.ndarray`
--    """
--    return _id.idzr_aidi(m, n, k)
--
--
--#------------------------------------------------------------------------------
--# idzr_asvd.f
--#------------------------------------------------------------------------------
--
--def idzr_asvd(A, k):
--    """
--    Compute SVD of a complex matrix to a specified rank using random sampling.
--
--    :param A:
--        Matrix.
--    :type A: :class:`numpy.ndarray`
--    :param k:
--        Rank of SVD.
--    :type k: int
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    A = np.asfortranarray(A)
--    m, n = A.shape
--    w = np.empty(
--        (2*k + 22)*m + (6*k + 21)*n + 8*k**2 + 10*k + 90,
--        dtype='complex128', order='F')
--    w_ = idzr_aidi(m, n, k)
--    w[:w_.size] = w_
--    U, V, S, ier = _id.idzr_asvd(A, k, w)
--    if ier:
--        raise _RETCODE_ERROR
--    return U, V, S
--
--
--#------------------------------------------------------------------------------
--# idzr_rid.f
--#------------------------------------------------------------------------------
--
--def idzr_rid(m, n, matveca, k):
--    """
--    Compute ID of a complex matrix to a specified rank using random
--    matrix-vector multiplication.
--
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matveca:
--        Function to apply the matrix adjoint to a vector, with call signature
--        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matveca: function
--    :param k:
--        Rank of ID.
--    :type k: int
--
--    :return:
--        Column index array.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Interpolation coefficients.
--    :rtype: :class:`numpy.ndarray`
--    """
--    idx, proj = _id.idzr_rid(m, n, matveca, k)
--    proj = proj[:k*(n-k)].reshape((k, n-k), order='F')
--    return idx, proj
--
--
--#------------------------------------------------------------------------------
--# idzr_rsvd.f
--#------------------------------------------------------------------------------
--
--def idzr_rsvd(m, n, matveca, matvec, k):
--    """
--    Compute SVD of a complex matrix to a specified rank using random
--    matrix-vector multiplication.
--
--    :param m:
--        Matrix row dimension.
--    :type m: int
--    :param n:
--        Matrix column dimension.
--    :type n: int
--    :param matveca:
--        Function to apply the matrix adjoint to a vector, with call signature
--        `y = matveca(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matveca: function
--    :param matvec:
--        Function to apply the matrix to a vector, with call signature
--        `y = matvec(x)`, where `x` and `y` are the input and output vectors,
--        respectively.
--    :type matvec: function
--    :param k:
--        Rank of SVD.
--    :type k: int
--
--    :return:
--        Left singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Right singular vectors.
--    :rtype: :class:`numpy.ndarray`
--    :return:
--        Singular values.
--    :rtype: :class:`numpy.ndarray`
--    """
--    U, V, S, ier = _id.idzr_rsvd(m, n, matveca, matvec, k)
--    if ier:
--        raise _RETCODE_ERROR
--    return U, V, S
-diff --git a/scipy/linalg/interpolative.py b/scipy/linalg/interpolative.py
-index b91cdd63a..f946b059f 100644
---- a/scipy/linalg/interpolative.py
-+++ b/scipy/linalg/interpolative.py
-@@ -1,4 +1,4 @@
--#******************************************************************************
-+#  ******************************************************************************
- #   Copyright (C) 2013 Kenneth L. Ho
- #
- #   Redistribution and use in source and binary forms, with or without
-@@ -25,19 +25,19 @@
- #   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- #   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- #   POSSIBILITY OF SUCH DAMAGE.
--#******************************************************************************
--
--# Python module for interfacing with `id_dist`.
-+#  ******************************************************************************
- 
- r"""
- ======================================================================
- Interpolative matrix decomposition (:mod:`scipy.linalg.interpolative`)
- ======================================================================
- 
--.. moduleauthor:: Kenneth L. Ho 
--
- .. versionadded:: 0.13
- 
-+.. versionchanged:: 1.15.0
-+    The underlying algorithms have been ported to Python from the original Fortran77
-+    code. See references below for more details.
-+
- .. currentmodule:: scipy.linalg.interpolative
- 
- An interpolative decomposition (ID) of a matrix :math:`A \in
-@@ -94,7 +94,7 @@ Main functionality:
-    estimate_spectral_norm_diff
-    estimate_rank
- 
--Support functions:
-+Following support functions are deprecated and will be removed in SciPy 1.17.0:
- 
- .. autosummary::
-    :toctree: generated/
-@@ -106,16 +106,13 @@ Support functions:
- References
- ==========
- 
--This module uses the ID software package [1]_ by Martinsson, Rokhlin,
--Shkolnisky, and Tygert, which is a Fortran library for computing IDs
--using various algorithms, including the rank-revealing QR approach of
--[2]_ and the more recent randomized methods described in [3]_, [4]_,
--and [5]_. This module exposes its functionality in a way convenient
--for Python users. Note that this module does not add any functionality
--beyond that of organizing a simpler and more consistent interface.
-+This module uses the algorithms found in ID software package [1]_ by Martinsson,
-+Rokhlin, Shkolnisky, and Tygert, which is a Fortran library for computing IDs using
-+various algorithms, including the rank-revealing QR approach of [2]_ and the more
-+recent randomized methods described in [3]_, [4]_, and [5]_.
- 
--We advise the user to consult also the `documentation for the ID package
--`_.
-+We advise the user to consult also the documentation for the `ID package
-+`_.
- 
- .. [1] P.G. Martinsson, V. Rokhlin, Y. Shkolnisky, M. Tygert. "ID: a
-     software package for low-rank approximation of matrices via interpolative
-@@ -356,25 +353,8 @@ depending on the representation. The parameter ``eps`` controls the definition
- of the numerical rank.
- 
- Finally, the random number generation required for all randomized routines can
--be controlled via :func:`scipy.linalg.interpolative.seed`. To reset the seed
--values to their original values, use:
--
-->>> sli.seed('default')
--
--To specify the seed values, use:
--
-->>> s = 42
-->>> sli.seed(s)
--
--where ``s`` must be an integer or array of 55 floats. If an integer, the array
--of floats is obtained by using ``numpy.random.rand`` with the given integer
--seed.
--
--To simply generate some random numbers, type:
--
-->>> arr = sli.rand(n)
--
--where ``n`` is the number of random numbers to generate.
-+be controlled via providing NumPy pseudo-random generators with a fixed seed. See
-+:class:`numpy.random.Generator` and :func:`numpy.random.default_rng` for more details.
- 
- Remarks
- -------
-@@ -385,9 +365,9 @@ backend routine.
- 
- """
- 
--import scipy.linalg._interpolative_backend as _backend
-+import scipy.linalg._decomp_interpolative as _backend
- import numpy as np
--import sys
-+import warnings
- 
- __all__ = [
-     'estimate_rank',
-@@ -405,9 +385,18 @@ __all__ = [
- 
- _DTYPE_ERROR = ValueError("invalid input dtype (input must be float64 or complex128)")
- _TYPE_ERROR = TypeError("invalid input type (must be array or LinearOperator)")
--_32BIT_ERROR = ValueError("interpolative decomposition on 32-bit systems "
--                          "with complex128 is buggy")
--_IS_32BIT = (sys.maxsize < 2**32)
-+
-+
-+def _C_contiguous_copy(A):
-+    """
-+    Same as np.ascontiguousarray, but ensure a copy
-+    """
-+    A = np.asarray(A)
-+    if A.flags.c_contiguous:
-+        A = A.copy()
-+    else:
-+        A = np.ascontiguousarray(A)
-+    return A
- 
- 
- def _is_real(A):
-@@ -424,53 +413,29 @@ def _is_real(A):
- 
- def seed(seed=None):
-     """
--    Seed the internal random number generator used in this ID package.
--
--    The generator is a lagged Fibonacci method with 55-element internal state.
--
--    Parameters
--    ----------
--    seed : int, sequence, 'default', optional
--        If 'default', the random seed is reset to a default value.
--
--        If `seed` is a sequence containing 55 floating-point numbers
--        in range [0,1], these are used to set the internal state of
--        the generator.
--
--        If the value is an integer, the internal state is obtained
--        from `numpy.random.RandomState` (MT19937) with the integer
--        used as the initial seed.
--
--        If `seed` is omitted (None), ``numpy.random.rand`` is used to
--        initialize the generator.
-+    This function, historically, used to set the seed of the randomization algorithms
-+    used in the `scipy.linalg.interpolative` functions written in Fortran77.
- 
-+    The library has been ported to Python and now the functions use the native NumPy
-+    generators and this function has no content and returns None. Thus this function
-+    should not be used and will be removed in SciPy version 1.17.0.
-     """
--    # For details, see :func:`_backend.id_srand`, :func:`_backend.id_srandi`,
--    # and :func:`_backend.id_srando`.
--
--    if isinstance(seed, str) and seed == 'default':
--        _backend.id_srando()
--    elif hasattr(seed, '__len__'):
--        state = np.asfortranarray(seed, dtype=float)
--        if state.shape != (55,):
--            raise ValueError("invalid input size")
--        elif state.min() < 0 or state.max() > 1:
--            raise ValueError("values not in range [0,1]")
--        _backend.id_srandi(state)
--    elif seed is None:
--        _backend.id_srandi(np.random.rand(55))
--    else:
--        rnd = np.random.RandomState(seed)
--        _backend.id_srandi(rnd.rand(55))
-+    warnings.warn("`scipy.linalg.interpolative.seed` is deprecated and will be "
-+                  "removed in SciPy 1.17.0.", DeprecationWarning, stacklevel=3)
- 
- 
- def rand(*shape):
-     """
--    Generate standard uniform pseudorandom numbers via a very efficient lagged
--    Fibonacci method.
-+    This function, historically, used to generate uniformly distributed random number
-+    for the randomization algorithms used in the `scipy.linalg.interpolative` functions
-+    written in Fortran77.
- 
--    This routine is used for all random number generation in this package and
--    can affect ID and SVD results.
-+    The library has been ported to Python and now the functions use the native NumPy
-+    generators. Thus this function should not be used and will be removed in the
-+    SciPy version 1.17.0.
-+
-+    If pseudo-random numbers are needed, NumPy pseudo-random generators should be used
-+    instead.
- 
-     Parameters
-     ----------
-@@ -478,11 +443,13 @@ def rand(*shape):
-         Shape of output array
- 
-     """
--    # For details, see :func:`_backend.id_srand`, and :func:`_backend.id_srando`.
--    return _backend.id_srand(np.prod(shape)).reshape(shape)
-+    warnings.warn("`scipy.linalg.interpolative.rand` is deprecated and will be "
-+                  "removed in SciPy 1.17.0.", DeprecationWarning, stacklevel=3)
-+    rng = np.random.default_rng()
-+    return rng.uniform(low=0., high=1.0, size=shape)
- 
- 
--def interp_decomp(A, eps_or_k, rand=True):
-+def interp_decomp(A, eps_or_k, rand=True, rng=None):
-     """
-     Compute ID of a matrix.
- 
-@@ -546,6 +513,9 @@ def interp_decomp(A, eps_or_k, rand=True):
-         Whether to use random sampling if `A` is of type :class:`numpy.ndarray`
-         (randomized algorithms are always used if `A` is of type
-         :class:`scipy.sparse.linalg.LinearOperator`).
-+    rng : :class:`numpy.random.Generator`
-+        NumPy generator for the randomization steps in the algorithm. If ``rand`` is
-+        ``False``, the argument is ignored.
- 
-     Returns
-     -------
-@@ -562,57 +532,49 @@ def interp_decomp(A, eps_or_k, rand=True):
-     real = _is_real(A)
- 
-     if isinstance(A, np.ndarray):
-+        A = _C_contiguous_copy(A)
-         if eps_or_k < 1:
-             eps = eps_or_k
-             if rand:
-                 if real:
--                    k, idx, proj = _backend.iddp_aid(eps, A)
-+                    k, idx, proj = _backend.iddp_aid(A, eps, rng=rng)
-                 else:
--                    if _IS_32BIT:
--                        raise _32BIT_ERROR
--                    k, idx, proj = _backend.idzp_aid(eps, A)
-+                    k, idx, proj = _backend.idzp_aid(A, eps, rng=rng)
-             else:
-                 if real:
--                    k, idx, proj = _backend.iddp_id(eps, A)
-+                    k, idx, proj = _backend.iddp_id(A, eps)
-                 else:
--                    k, idx, proj = _backend.idzp_id(eps, A)
--            return k, idx - 1, proj
-+                    k, idx, proj = _backend.idzp_id(A, eps)
-+            return k, idx, proj
-         else:
-             k = int(eps_or_k)
-             if rand:
-                 if real:
--                    idx, proj = _backend.iddr_aid(A, k)
-+                    idx, proj = _backend.iddr_aid(A, k, rng=rng)
-                 else:
--                    if _IS_32BIT:
--                        raise _32BIT_ERROR
--                    idx, proj = _backend.idzr_aid(A, k)
-+                    idx, proj = _backend.idzr_aid(A, k, rng=rng)
-             else:
-                 if real:
-                     idx, proj = _backend.iddr_id(A, k)
-                 else:
-                     idx, proj = _backend.idzr_id(A, k)
--            return idx - 1, proj
-+            return idx, proj
-     elif isinstance(A, LinearOperator):
--        m, n = A.shape
--        matveca = A.rmatvec
-+
-         if eps_or_k < 1:
-             eps = eps_or_k
-             if real:
--                k, idx, proj = _backend.iddp_rid(eps, m, n, matveca)
-+                k, idx, proj = _backend.iddp_rid(A, eps, rng=rng)
-             else:
--                if _IS_32BIT:
--                    raise _32BIT_ERROR
--                k, idx, proj = _backend.idzp_rid(eps, m, n, matveca)
--            return k, idx - 1, proj
-+                k, idx, proj = _backend.idzp_rid(A, eps, rng=rng)
-+            return k, idx, proj
-         else:
-             k = int(eps_or_k)
-             if real:
--                idx, proj = _backend.iddr_rid(m, n, matveca, k)
-+                idx, proj = _backend.iddr_rid(A, k, rng=rng)
-             else:
--                if _IS_32BIT:
--                    raise _32BIT_ERROR
--                idx, proj = _backend.idzr_rid(m, n, matveca, k)
--            return idx - 1, proj
-+                idx, proj = _backend.idzr_rid(A, k, rng=rng)
-+            return idx, proj
-     else:
-         raise _TYPE_ERROR
- 
-@@ -648,9 +610,9 @@ def reconstruct_matrix_from_id(B, idx, proj):
-         Reconstructed matrix.
-     """
-     if _is_real(B):
--        return _backend.idd_reconid(B, idx + 1, proj)
-+        return _backend.idd_reconid(B, idx, proj)
-     else:
--        return _backend.idz_reconid(B, idx + 1, proj)
-+        return _backend.idz_reconid(B, idx, proj)
- 
- 
- def reconstruct_interp_matrix(idx, proj):
-@@ -662,10 +624,8 @@ def reconstruct_interp_matrix(idx, proj):
- 
-         P = numpy.hstack([numpy.eye(proj.shape[0]), proj])[:,numpy.argsort(idx)]
- 
--    The original matrix can then be reconstructed from its skeleton matrix `B`
--    via::
--
--        numpy.dot(B, P)
-+    The original matrix can then be reconstructed from its skeleton matrix ``B``
-+    via ``A = B @ P``
- 
-     See also :func:`reconstruct_matrix_from_id` and
-     :func:`reconstruct_skel_matrix`.
-@@ -677,7 +637,7 @@ def reconstruct_interp_matrix(idx, proj):
-     Parameters
-     ----------
-     idx : :class:`numpy.ndarray`
--        Column index array.
-+        1D column index array.
-     proj : :class:`numpy.ndarray`
-         Interpolation coefficients.
- 
-@@ -686,10 +646,17 @@ def reconstruct_interp_matrix(idx, proj):
-     :class:`numpy.ndarray`
-         Interpolation matrix.
-     """
-+    n, krank = len(idx), proj.shape[0]
-     if _is_real(proj):
--        return _backend.idd_reconint(idx + 1, proj)
-+        p = np.zeros([krank, n], dtype=np.float64)
-     else:
--        return _backend.idz_reconint(idx + 1, proj)
-+        p = np.zeros([krank, n], dtype=np.complex128)
-+
-+    for ci in range(krank):
-+        p[ci, idx[ci]] = 1.0
-+    p[:, idx[krank:]] = proj[:, :]
-+
-+    return p
- 
- 
- def reconstruct_skel_matrix(A, k, idx):
-@@ -726,10 +693,7 @@ def reconstruct_skel_matrix(A, k, idx):
-     :class:`numpy.ndarray`
-         Skeleton matrix.
-     """
--    if _is_real(A):
--        return _backend.idd_copycols(A, k, idx + 1)
--    else:
--        return _backend.idz_copycols(A, k, idx + 1)
-+    return A[:, idx[:k]]
- 
- 
- def id_to_svd(B, idx, proj):
-@@ -753,7 +717,7 @@ def id_to_svd(B, idx, proj):
-     B : :class:`numpy.ndarray`
-         Skeleton matrix.
-     idx : :class:`numpy.ndarray`
--        Column index array.
-+        1D column index array.
-     proj : :class:`numpy.ndarray`
-         Interpolation coefficients.
- 
-@@ -766,14 +730,16 @@ def id_to_svd(B, idx, proj):
-     V : :class:`numpy.ndarray`
-         Right singular vectors.
-     """
-+    B = _C_contiguous_copy(B)
-     if _is_real(B):
--        U, V, S = _backend.idd_id2svd(B, idx + 1, proj)
-+        U, S, V = _backend.idd_id2svd(B, idx, proj)
-     else:
--        U, V, S = _backend.idz_id2svd(B, idx + 1, proj)
-+        U, S, V = _backend.idz_id2svd(B, idx, proj)
-+
-     return U, S, V
- 
- 
--def estimate_spectral_norm(A, its=20):
-+def estimate_spectral_norm(A, its=20, rng=None):
-     """
-     Estimate spectral norm of a matrix by the randomized power method.
- 
-@@ -788,6 +754,8 @@ def estimate_spectral_norm(A, its=20):
-         `matvec` and `rmatvec` methods (to apply the matrix and its adjoint).
-     its : int, optional
-         Number of power method iterations.
-+    rng : :class:`numpy.random.Generator`
-+        NumPy generator for the randomization steps in the algorithm.
- 
-     Returns
-     -------
-@@ -796,18 +764,14 @@ def estimate_spectral_norm(A, its=20):
-     """
-     from scipy.sparse.linalg import aslinearoperator
-     A = aslinearoperator(A)
--    m, n = A.shape
--    def matvec(x):
--        return A.matvec(x)
--    def matveca(x):
--        return A.rmatvec(x)
-+
-     if _is_real(A):
--        return _backend.idd_snorm(m, n, matveca, matvec, its=its)
-+        return _backend.idd_snorm(A, its=its, rng=rng)
-     else:
--        return _backend.idz_snorm(m, n, matveca, matvec, its=its)
-+        return _backend.idz_snorm(A, its=its, rng=rng)
- 
- 
--def estimate_spectral_norm_diff(A, B, its=20):
-+def estimate_spectral_norm_diff(A, B, its=20, rng=None):
-     """
-     Estimate spectral norm of the difference of two matrices by the randomized
-     power method.
-@@ -826,6 +790,8 @@ def estimate_spectral_norm_diff(A, B, its=20):
-         the `matvec` and `rmatvec` methods (to apply the matrix and its adjoint).
-     its : int, optional
-         Number of power method iterations.
-+    rng : :class:`numpy.random.Generator`
-+        NumPy generator for the randomization steps in the algorithm.
- 
-     Returns
-     -------
-@@ -835,30 +801,20 @@ def estimate_spectral_norm_diff(A, B, its=20):
-     from scipy.sparse.linalg import aslinearoperator
-     A = aslinearoperator(A)
-     B = aslinearoperator(B)
--    m, n = A.shape
--    def matvec1(x):
--        return A.matvec(x)
--    def matveca1(x):
--        return A.rmatvec(x)
--    def matvec2(x):
--        return B.matvec(x)
--    def matveca2(x):
--        return B.rmatvec(x)
-+
-     if _is_real(A):
--        return _backend.idd_diffsnorm(
--            m, n, matveca1, matveca2, matvec1, matvec2, its=its)
-+        return _backend.idd_diffsnorm(A, B, its=its, rng=rng)
-     else:
--        return _backend.idz_diffsnorm(
--            m, n, matveca1, matveca2, matvec1, matvec2, its=its)
-+        return _backend.idz_diffsnorm(A, B, its=its, rng=rng)
- 
- 
--def svd(A, eps_or_k, rand=True):
-+def svd(A, eps_or_k, rand=True, rng=None):
-     """
-     Compute SVD of a matrix via an ID.
- 
-     An SVD of a matrix `A` is a factorization::
- 
--        A = numpy.dot(U, numpy.dot(numpy.diag(S), V.conj().T))
-+        A = U @ np.diag(S) @ V.conj().T
- 
-     where `U` and `V` have orthonormal columns and `S` is nonnegative.
- 
-@@ -889,35 +845,39 @@ def svd(A, eps_or_k, rand=True):
-         Whether to use random sampling if `A` is of type :class:`numpy.ndarray`
-         (randomized algorithms are always used if `A` is of type
-         :class:`scipy.sparse.linalg.LinearOperator`).
-+    rng : :class:`numpy.random.Generator`
-+        NumPy generator for the randomization steps in the algorithm. If ``rand`` is
-+        ``False``, the argument is ignored.
- 
-     Returns
-     -------
-     U : :class:`numpy.ndarray`
--        Left singular vectors.
-+        2D array of left singular vectors.
-     S : :class:`numpy.ndarray`
--        Singular values.
-+        1D array of singular values.
-     V : :class:`numpy.ndarray`
--        Right singular vectors.
-+        2D array right singular vectors.
-     """
-     from scipy.sparse.linalg import LinearOperator
- 
-     real = _is_real(A)
- 
-     if isinstance(A, np.ndarray):
-+        A = _C_contiguous_copy(A)
-         if eps_or_k < 1:
-             eps = eps_or_k
-             if rand:
-                 if real:
--                    U, V, S = _backend.iddp_asvd(eps, A)
-+                    U, S, V = _backend.iddp_asvd(A, eps, rng=rng)
-                 else:
--                    if _IS_32BIT:
--                        raise _32BIT_ERROR
--                    U, V, S = _backend.idzp_asvd(eps, A)
-+                    U, S, V = _backend.idzp_asvd(A, eps, rng=rng)
-             else:
-                 if real:
--                    U, V, S = _backend.iddp_svd(eps, A)
-+                    U, S, V = _backend.iddp_svd(A, eps)
-+                    V = V.T.conj()
-                 else:
--                    U, V, S = _backend.idzp_svd(eps, A)
-+                    U, S, V = _backend.idzp_svd(A, eps)
-+                    V = V.T.conj()
-         else:
-             k = int(eps_or_k)
-             if k > min(A.shape):
-@@ -925,44 +885,35 @@ def svd(A, eps_or_k, rand=True):
-                                  f" {min(A.shape)} ")
-             if rand:
-                 if real:
--                    U, V, S = _backend.iddr_asvd(A, k)
-+                    U, S, V = _backend.iddr_asvd(A, k, rng=rng)
-                 else:
--                    if _IS_32BIT:
--                        raise _32BIT_ERROR
--                    U, V, S = _backend.idzr_asvd(A, k)
-+                    U, S, V = _backend.idzr_asvd(A, k, rng=rng)
-             else:
-                 if real:
--                    U, V, S = _backend.iddr_svd(A, k)
-+                    U, S, V = _backend.iddr_svd(A, k)
-+                    V = V.T.conj()
-                 else:
--                    U, V, S = _backend.idzr_svd(A, k)
-+                    U, S, V = _backend.idzr_svd(A, k)
-+                    V = V.T.conj()
-     elif isinstance(A, LinearOperator):
--        m, n = A.shape
--        def matvec(x):
--            return A.matvec(x)
--        def matveca(x):
--            return A.rmatvec(x)
-         if eps_or_k < 1:
-             eps = eps_or_k
-             if real:
--                U, V, S = _backend.iddp_rsvd(eps, m, n, matveca, matvec)
-+                U, S, V = _backend.iddp_rsvd(A, eps, rng=rng)
-             else:
--                if _IS_32BIT:
--                    raise _32BIT_ERROR
--                U, V, S = _backend.idzp_rsvd(eps, m, n, matveca, matvec)
-+                U, S, V = _backend.idzp_rsvd(A, eps, rng=rng)
-         else:
-             k = int(eps_or_k)
-             if real:
--                U, V, S = _backend.iddr_rsvd(m, n, matveca, matvec, k)
-+                U, S, V = _backend.iddr_rsvd(A, k, rng=rng)
-             else:
--                if _IS_32BIT:
--                    raise _32BIT_ERROR
--                U, V, S = _backend.idzr_rsvd(m, n, matveca, matvec, k)
-+                U, S, V = _backend.idzr_rsvd(A, k, rng=rng)
-     else:
-         raise _TYPE_ERROR
-     return U, S, V
- 
- 
--def estimate_rank(A, eps):
-+def estimate_rank(A, eps, rng=None):
-     """
-     Estimate matrix rank to a specified relative precision using randomized
-     methods.
-@@ -985,6 +936,8 @@ def estimate_rank(A, eps):
-         with the `rmatvec` method (to apply the matrix adjoint).
-     eps : float
-         Relative error for numerical rank definition.
-+    rng : :class:`numpy.random.Generator`
-+        NumPy generator for the randomization steps in the algorithm.
- 
-     Returns
-     -------
-@@ -996,20 +949,19 @@ def estimate_rank(A, eps):
-     real = _is_real(A)
- 
-     if isinstance(A, np.ndarray):
-+        A = _C_contiguous_copy(A)
-         if real:
--            rank = _backend.idd_estrank(eps, A)
-+            rank, _ = _backend.idd_estrank(A, eps, rng=rng)
-         else:
--            rank = _backend.idz_estrank(eps, A)
-+            rank, _ = _backend.idz_estrank(A, eps, rng=rng)
-         if rank == 0:
-             # special return value for nearly full rank
-             rank = min(A.shape)
-         return rank
-     elif isinstance(A, LinearOperator):
--        m, n = A.shape
--        matveca = A.rmatvec
-         if real:
--            return _backend.idd_findrank(eps, m, n, matveca)
-+            return _backend.idd_findrank(A, eps, rng=rng)[0]
-         else:
--            return _backend.idz_findrank(eps, m, n, matveca)
-+            return _backend.idz_findrank(A, eps, rng=rng)[0]
-     else:
-         raise _TYPE_ERROR
-diff --git a/scipy/linalg/meson.build b/scipy/linalg/meson.build
-index cc208092e..777edd008 100644
---- a/scipy/linalg/meson.build
-+++ b/scipy/linalg/meson.build
-@@ -111,57 +111,15 @@ py3.extension_module('_flapack',
- 
- # TODO: cblas/clapack are built *only* for ATLAS. Why? Is it still needed?
- 
--# id_dist contains a copy of FFTPACK, which has type mismatch warnings
--# that are hard to fix. This code is terrible and noisy during the build,
--# silence it completely.
--_suppress_all_warnings = ff.get_supported_arguments('-w')
--
--py3.extension_module('_interpolative',
--  [
--    'src/id_dist/src/dfft.f',
--    'src/id_dist/src/id_rand.f',
--    'src/id_dist/src/id_rtrans.f',
--    'src/id_dist/src/idd_frm.f',
--    'src/id_dist/src/idd_house.f',
--    'src/id_dist/src/idd_id.f',
--    'src/id_dist/src/idd_id2svd.f',
--    'src/id_dist/src/idd_qrpiv.f',
--    'src/id_dist/src/idd_sfft.f',
--    'src/id_dist/src/idd_snorm.f',
--    'src/id_dist/src/idd_svd.f',
--    'src/id_dist/src/iddp_aid.f',
--    'src/id_dist/src/iddp_asvd.f',
--    'src/id_dist/src/iddp_rid.f',
--    'src/id_dist/src/iddp_rsvd.f',
--    'src/id_dist/src/iddr_aid.f',
--    'src/id_dist/src/iddr_asvd.f',
--    'src/id_dist/src/iddr_rid.f',
--    'src/id_dist/src/iddr_rsvd.f',
--    'src/id_dist/src/idz_frm.f',
--    'src/id_dist/src/idz_house.f',
--    'src/id_dist/src/idz_id.f',
--    'src/id_dist/src/idz_id2svd.f',
--    'src/id_dist/src/idz_qrpiv.f',
--    'src/id_dist/src/idz_sfft.f',
--    'src/id_dist/src/idz_snorm.f',
--    'src/id_dist/src/idz_svd.f',
--    'src/id_dist/src/idzp_aid.f',
--    'src/id_dist/src/idzp_asvd.f',
--    'src/id_dist/src/idzp_rid.f',
--    'src/id_dist/src/idzp_rsvd.f',
--    'src/id_dist/src/idzr_aid.f',
--    'src/id_dist/src/idzr_asvd.f',
--    'src/id_dist/src/idzr_rid.f',
--    'src/id_dist/src/idzr_rsvd.f',
--    'src/id_dist/src/prini.f',
--    f2py_gen.process('interpolative.pyf'),
--  ],
--  fortran_args: [fortran_ignore_warnings, _suppress_all_warnings],
-+# _decomp_interpolative
-+py3.extension_module('_decomp_interpolative',
-+  linalg_init_cython_gen.process('_decomp_interpolative.pyx'),
-+  c_args: cython_c_args,
-+  dependencies: np_dep,
-+  c_args: numpy_nodepr_api,
-   link_args: version_link_args,
--  dependencies: [lapack_dep, fortranobject_dep],
-   override_options: ['b_lto=false'],
-   install: true,
--  link_language: 'fortran',
-   subdir: 'scipy/linalg'
- )
- 
-@@ -278,7 +236,6 @@ python_sources = [
-   '_decomp_schur.py',
-   '_decomp_svd.py',
-   '_expm_frechet.py',
--  '_interpolative_backend.py',
-   '_matfuncs.py',
-   '_matfuncs_expm.pyi',
-   '_matfuncs_inv_ssq.py',
-diff --git a/scipy/linalg/src/id_dist/README.txt b/scipy/linalg/src/id_dist/README.txt
-deleted file mode 100644
-index 000bb1e5f..000000000
---- a/scipy/linalg/src/id_dist/README.txt
-+++ /dev/null
-@@ -1,6 +0,0 @@
--Please see the documentation in subdirectory doc of this id_dist directory.
--
--At the minimum, please read Subsection 2.1 and Section 3 in the documentation,
--and beware that the _N.B._'s in the source code comments highlight important
--information about the routines -- _N.B._ stands for _nota_bene_ (Latin for
--"note well").
-diff --git a/scipy/linalg/src/id_dist/doc/doc.bib b/scipy/linalg/src/id_dist/doc/doc.bib
-deleted file mode 100644
-index 1ab5cb220..000000000
---- a/scipy/linalg/src/id_dist/doc/doc.bib
-+++ /dev/null
-@@ -1,19 +0,0 @@
--@book{golub-van_loan,
--  author = {Gene Golub and Charles {Van L}oan},
--  title = {Matrix Computations},
--  edition = {Third},
--  publisher = {Johns Hopkins University Press},
--  year = {1996},
--  address = {Baltimore, Maryland}
--}
--
--@article{halko-martinsson-tropp,
--  author = {Nathan Halko and {P.-G.} Martinsson and Joel A. Tropp},
--  title = {Finding structure with randomness: probabilistic algorithms
--           for constructing approximate matrix decompositions},
--  journal = {SIAM Review},
--  volume = {53},
--  number = {2},
--  pages = {217--288},
--  year = {2011}
--}
-diff --git a/scipy/linalg/src/id_dist/doc/doc.tex b/scipy/linalg/src/id_dist/doc/doc.tex
-deleted file mode 100644
-index 8bcece8c4..000000000
---- a/scipy/linalg/src/id_dist/doc/doc.tex
-+++ /dev/null
-@@ -1,977 +0,0 @@
--\documentclass[letterpaper,12pt]{article}
--\usepackage[margin=1in]{geometry}
--\usepackage{verbatim}
--\usepackage{amsmath}
--\usepackage{supertabular}
--\usepackage{array}
--
--\def\T{{\hbox{\scriptsize{\rm T}}}}
--\def\epsilon{\varepsilon}
--\def\bigoh{\mathcal{O}}
--\def\phi{\varphi}
--\def\st{{\hbox{\scriptsize{\rm st}}}}
--\def\th{{\hbox{\scriptsize{\rm th}}}}
--\def\x{\mathbf{x}}
--
--
--\title{ID: A software package for low-rank approximation
--       of matrices via interpolative decompositions, Version 0.4}
--\author{Per-Gunnar Martinsson, Vladimir Rokhlin,\\
--        Yoel Shkolnisky, and Mark Tygert}
--
--
--\begin{document}
--
--\maketitle
--
--\newpage
--
--{\parindent=0pt
--
--The present document and all of the software
--in the accompanying distribution (which is contained in the directory
--{\tt id\_dist} and its subdirectories, or in the file
--{\tt id\_dist.tar.gz})\, is
--
--\bigskip
--
--Copyright \copyright\ 2014 by P.-G. Martinsson, V. Rokhlin,
--Y. Shkolnisky, and M. Tygert.
--
--\bigskip
--
--All rights reserved.
--
--\bigskip
--
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are
--met:
--
--\begin{enumerate}
--\item Redistributions of source code must retain the above copyright
--notice, this list of conditions, and the following disclaimer.
--\item Redistributions in binary form must reproduce the above copyright
--notice, this list of conditions, and the following disclaimer in the
--documentation and/or other materials provided with the distribution.
--\item None of the names of the copyright holders may be used to endorse
--or promote products derived from this software without specific prior
--written permission.
--\end{enumerate}
--
--\bigskip
--
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
--EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
--IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
--PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNERS BE
--LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
--CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
--SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
--BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
--WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
--OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
--ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
--}
--
--\newpage
--
--\tableofcontents
--
--\newpage
--
--
--
--\hrule
--
--\medskip
--
--\centerline{\Large \bf IMPORTANT}
--
--\medskip
--
--\hrule
--
--\medskip
--
--\noindent At the minimum, please read Subsection~\ref{warning}
--and Section~\ref{naming} below, and beware that the {\it N.B.}'s
--in the source code comments highlight key information about the routines;
--{\it N.B.} stands for {\it nota bene} (Latin for ``note well'').
--
--\medskip
--
--\hrule
--
--\bigskip
--
--
--
--\section{Introduction}
--
--This software distribution provides Fortran routines
--for computing low-rank approximations to matrices,
--in the forms of interpolative decompositions (IDs)
--and singular value decompositions (SVDs).
--The routines use algorithms based on the ID.
--The ID is also commonly known as
--the approximation obtained via skeletonization,
--the approximation obtained via subsampling,
--and the approximation obtained via subset selection.
--The ID provides many advantages in many applications,
--and we suspect that it will become increasingly popular
--once tools for its computation become more widely available.
--This software distribution includes some such tools,
--as well as tools for computing low-rank approximations
--in the form of SVDs.
--Section~\ref{defs} below defines IDs and SVDs,
--and provides references to detailed discussions of the algorithms
--used in this software package.
--
--Please beware that normalized power iterations are better suited than
--the software in this distribution
--for computing principal component analyses
--in the typical case when the square of the signal-to-noise ratio
--is not orders of magnitude greater than both dimensions
--of the data matrix; see~\cite{halko-martinsson-tropp}.
--
--The algorithms used in this distribution have been optimized
--for accuracy, efficiency, and reliability;
--as a somewhat counterintuitive consequence, many must be randomized.
--All randomized codes in this software package succeed
--with overwhelmingly high probability (see, for example,
--\cite{halko-martinsson-tropp}).
--The truly paranoid are welcome to use the routines {\tt idd\_diffsnorm}
--and {\tt idz\_diffsnorm} to evaluate rapidly the quality
--of the approximations produced by the randomized algorithms
--(as done, for example, in the files
--{\tt idd\_a\_test.f}, {\tt idd\_r\_test.f}, {\tt idz\_a\_test.f},
--and {\tt idz\_r\_test.f} in the {\tt test} subdirectory
--of the main directory {\tt id\_dist}).
--In most circumstances, evaluating the quality of an approximation
--via routines {\tt idd\_diffsnorm} or {\tt idz\_diffsnorm} is much faster
--than forming the approximation to be evaluated. Still, we are unaware
--of any instance in which a properly-compiled routine failed to produce
--an accurate approximation.
--To facilitate successful compilation, we encourage the user
--to read the instructions in the next section,
--and to read Section~\ref{naming}, too.
--
--
--
--\section{Compilation instructions}
--
--
--Followed in numerical order, the subsections of this section
--provide step-by-step instructions for compiling the software
--under a Unix-compatible operating system.
--
--
--\subsection{Beware that default command-line flags may not be
--            sufficient for compiling the source codes!}
--\label{warning}
--
--The Fortran source codes in this distribution pass {\tt real*8}
--variables as integer variables, integers as {\tt real*8}'s,
--{\tt real*8}'s as {\tt complex*16}'s, and so on.
--This is common practice in numerical codes, and is not an error;
--be sure to provide the relevant command-line flags to the compiler
--(for example, run {\tt fort77} and {\tt f2c} with the flag {\tt -!P}).
--When following the compilation instructions
--in Subsection~\ref{makefile_edit} below,
--be sure to set {\tt FFLAGS} appropriately.
--
--
--\subsection{Install LAPACK}
--
--The SVD routines in this distribution depend on LAPACK.
--Before compiling the present distribution,
--create the LAPACK and BLAS archive (library) {\tt .a} files;
--information about installing LAPACK is available
--at {\tt http://www.netlib.org/lapack/} (and several other web sites).
--
--
--\subsection{Decompress and untar the file {\tt id\_dist.tar.gz}}
--
--At the command line, decompress and untar the file
--{\tt id\_dist.tar.gz} by issuing a command such as
--{\tt tar -xvvzf id\_dist.tar.gz}.
--This will create a directory named {\tt id\_dist}.
--
--
--\subsection{Edit the Makefile}
--\label{makefile_edit}
--
--The directory {\tt id\_dist} contains a file named {\tt Makefile}.
--In {\tt Makefile}, set the following:
--%
--\begin{itemize}
--\item {\tt FC} is the Fortran compiler.
--\item {\tt FFLAGS} is the set of command-line flags
--      (specifying optimization settings, for example)
--      for the Fortran compiler specified by {\tt FC};
--      please heed the warning in Subsection~\ref{warning} above!
--\item {\tt BLAS\_LIB} is the file-system path to the BLAS archive
--      (library) {\tt .a} file.
--\item {\tt LAPACK\_LIB} is the file-system path to the LAPACK archive
--      (library) {\tt .a} file.
--\item {\tt ARCH} is the archiver utility (usually {\tt ar}).
--\item {\tt ARCHFLAGS} is the set of command-line flags
--      for the archiver specified by {\tt ARCH} needed
--      to create an archive (usually {\tt cr}).
--\item {\tt RANLIB} is to be set to {\tt ranlib}
--      when {\tt ranlib} is available, and is to be set to {\tt echo}
--      when {\tt ranlib} is not available.
--\end{itemize}
--
--
--\subsection{Make and test the libraries}
--
--At the command line in a shell that adheres
--to the Bourne shell conventions for redirection, issue the command
--``{\tt make clean; make}'' to both create the archive (library)
--{\tt id\_lib.a} and test it.
--(In most modern Unix distributions, {\tt sh} is the Bourne shell,
--or else is fully compatible with the Bourne shell;
--the Korn shell {\tt ksh} and the Bourne-again shell {\tt bash}
--also use the Bourne shell conventions for redirection.)
--{\tt make} places the file {\tt id\_lib.a}
--in the directory {\tt id\_dist}; the archive (library) file
--{\tt id\_lib.a} contains machine code for all user-callable routines
--in this distribution.
--
--
--
--\section{Naming conventions}
--\label{naming}
--
--The names of routines and files in this distribution
--start with prefixes, followed by an underscore (``\_'').
--The prefixes are two to four characters in length,
--and have the following meanings:
--%
--\begin{itemize}
--\item The first two letters are always ``{\tt id}'',
--      the name of this distribution.
--\item The third letter (when present) is either ``{\tt d}''
--      or ``{\tt z}'';
--      ``{\tt d}'' stands for double precision ({\tt real*8}),
--      and ``{\tt z}'' stands for double complex ({\tt complex*16}).
--\item The fourth letter (when present) is either ``{\tt r}''
--      or ``{\tt p}'';
--      ``{\tt r}'' stands for specified rank,
--      and ``{\tt p}'' stands for specified precision.
--      The specified rank routines require the user to provide
--      the rank of the approximation to be constructed,
--      while the specified precision routines adjust the rank adaptively
--      to attain the desired precision.
--\end{itemize}
--
--For example, {\tt iddr\_aid} is a {\tt real*8} routine which computes
--an approximation of specified rank.
--{\tt idz\_snorm} is a {\tt complex*16} routine.
--{\tt id\_randperm} is yet another routine in this distribution.
--
--
--
--\section{Example programs}
--
--For examples of how to use the user-callable routines
--in this distribution, see the source codes in subdirectory {\tt test}
--of the main directory {\tt id\_dist}.
--
--
--
--\section{Directory structure}
--
--The main {\tt id\_dist} directory contains a Makefile,
--the auxiliary text files {\tt README.txt} and {\tt size.txt},
--and the following subdirectories, described in the subsections below:
--%
--\begin{enumerate}
--\item {\tt bin}
--\item {\tt development}
--\item {\tt doc}
--\item {\tt src}
--\item {\tt test}
--\item {\tt tmp}
--\end{enumerate}
--%
--If a ``{\tt make all}'' command has completed successfully,
--then the main {\tt id\_dist} directory will also contain
--an archive (library) file {\tt id\_lib.a} containing machine code
--for all of the user-callable routines.
--
--
--\subsection{Subdirectory {\tt bin}}
--
--Once all of the libraries have been made via the Makefile
--in the main {\tt id\_dist} directory,
--the subdirectory {\tt bin} will contain object files (machine code),
--each compiled from the corresponding file of source code
--in the subdirectory {\tt src} of {\tt id\_dist}.
--
--
--\subsection{Subdirectory {\tt development}}
--
--Each Fortran file in the subdirectory {\tt development}
--(except for {\tt dfft.f} and {\tt prini.f})
--specifies its dependencies at the top, then provides a main program
--for testing and debugging, and finally provides source code
--for a library of user-callable subroutines.
--The Fortran file {\tt dfft.f} is a copy of P. N. Swarztrauber's FFTPACK library
--for computing fast Fourier transforms.
--The Fortran file {\tt prini.f} is a copy of V. Rokhlin's library
--of formatted printing routines.
--Both {\tt dfft.f} (version 4) and {\tt prini.f} are in the public domain.
--The shell script {\tt RUNME.sh} runs shell scripts {\tt make\_src.sh}
--and {\tt make\_test.sh}, which fill the subdirectories {\tt src}
--and {\tt test} of the main directory {\tt id\_dist}
--with source codes for user-callable routines
--and with the main program testing codes.
--
--
--\subsection{Subdirectory {\tt doc}}
--
--Subdirectory {\tt doc} contains this documentation,
--supplementing comments in the source codes.
--
--
--\subsection{Subdirectory {\tt src}}
--
--The files in the subdirectory {\tt src} provide source code
--for software libraries. Each file in the subdirectory {\tt src}
--(except for {\tt dfft.f} and {\tt prini.f}) is
--the bottom part of the corresponding file
--in the subdirectory {\tt development} of {\tt id\_dist}.
--The file {\tt dfft.f} is just a copy
--of P. N. Swarztrauber's FFTPACK library
--for computing fast Fourier transforms.
--The file {\tt prini.f} is a copy of V. Rokhlin's library
--of formatted printing routines.
--Both {\tt dfft.f} (version 4) and {\tt prini.f} are in the public domain.
--
--
--\subsection{Subdirectory {\tt test}}
--
--The files in subdirectory {\tt test} provide source code
--for testing and debugging. Each file in subdirectory {\tt test} is
--the top part of the corresponding file
--in subdirectory {\tt development} of {\tt id\_dist},
--and provides a main program and a list of its dependencies.
--These codes provide examples of how to call the user-callable routines.
--
--
--
--\section{Catalog of the routines}
--
--The main routines for decomposing {\tt real*8} matrices are:
--%
--\begin{enumerate}
--%
--\item IDs of arbitrary (generally dense) matrices:
--{\tt iddp\_id}, {\tt iddr\_id}, {\tt iddp\_aid}, {\tt iddr\_aid}
--%
--\item IDs of matrices that may be rapidly applied to arbitrary vectors
--(as may the matrices' transposes):
--{\tt iddp\_rid}, {\tt iddr\_rid}
--%
--\item SVDs of arbitrary (generally dense) matrices:
--{\tt iddp\_svd}, {\tt iddr\_svd}, {\tt iddp\_asvd},\\{\tt iddr\_asvd}
--%
--\item SVDs of matrices that may be rapidly applied to arbitrary vectors
--(as may the matrices' transposes):
--{\tt iddp\_rsvd}, {\tt iddr\_rsvd}
--%
--\end{enumerate}
--
--Similarly, the main routines for decomposing {\tt complex*16} matrices
--are:
--%
--\begin{enumerate}
--%
--\item IDs of arbitrary (generally dense) matrices:
--{\tt idzp\_id}, {\tt idzr\_id}, {\tt idzp\_aid}, {\tt idzr\_aid}
--%
--\item IDs of matrices that may be rapidly applied to arbitrary vectors
--(as may the matrices' adjoints):
--{\tt idzp\_rid}, {\tt idzr\_rid}
--%
--\item SVDs of arbitrary (generally dense) matrices:
--{\tt idzp\_svd}, {\tt idzr\_svd}, {\tt idzp\_asvd},\\{\tt idzr\_asvd}
--%
--\item SVDs of matrices that may be rapidly applied to arbitrary vectors
--(as may the matrices' adjoints):
--{\tt idzp\_rsvd}, {\tt idzr\_rsvd}
--%
--\end{enumerate}
--
--This distribution also includes routines for constructing pivoted $QR$
--decompositions (in {\tt idd\_qrpiv.f} and {\tt idz\_qrpiv.f}), for
--estimating the spectral norms of matrices that may be applied rapidly
--to arbitrary vectors as may their adjoints (in {\tt idd\_snorm.f}
--and {\tt idz\_snorm.f}), for converting IDs to SVDs (in
--{\tt idd\_id2svd.f} and {\tt idz\_id2svd.f}), and for computing rapidly
--arbitrary subsets of the entries of the discrete Fourier transforms
--of vectors (in {\tt idd\_sfft.f} and {\tt idz\_sfft.f}).
--
--
--\subsection{List of the routines}
--
--The following is an alphabetical list of the routines
--in this distribution, together with brief descriptions
--of their functionality and the names of the files containing
--the routines' source code:
--
--\begin{center}
--%
--\tablehead{\bf Routine & \bf Description & \bf Source file \\}
--\tabletail{\hline}
--%
--\begin{supertabular}{>{\raggedright}p{1.2in} p{.53\textwidth} l}
--%
--\hline
--{\tt id\_frand} & generates pseudorandom numbers drawn uniformly from
--the interval $[0,1]$; this routine is more efficient than routine
--{\tt id\_srand}, but cannot generate fewer than 55 pseudorandom numbers
--per call & {\tt id\_rand.f} \\\hline
--%
--{\tt id\_frandi} & initializes the seed values for routine
--{\tt id\_frand} to specified values & {\tt id\_rand.f} \\\hline
--%
--{\tt id\_frando} & initializes the seed values for routine
--{\tt id\_frand} to their original, default values & {\tt id\_rand.f}
--\\\hline
--%
--{\tt id\_randperm} & generates a uniformly random permutation &
--{\tt id\_rand.f} \\\hline
--%
--{\tt id\_srand} & generates pseudorandom numbers drawn uniformly from
--the interval $[0,1]$; this routine is less efficient than routine
--{\tt id\_frand}, but can generate fewer than 55 pseudorandom numbers
--per call & {\tt id\_rand.f} \\\hline
--%
--{\tt id\_srandi} & initializes the seed values for routine
--{\tt id\_srand} to specified values & {\tt id\_rand.f} \\\hline
--%
--{\tt id\_srando} & initializes the seed values for routine
--{\tt id\_srand} to their original, default values & {\tt id\_rand.f}
--\\\hline
--%
--{\tt idd\_copycols} & collects together selected columns of a matrix &
--{\tt idd\_id.f} \\\hline
--%
--{\tt idd\_diffsnorm} & estimates the spectral norm of the difference
--between two matrices specified by routines for applying the matrices
--and their transposes to arbitrary vectors; this routine uses the power
--method with a random starting vector & {\tt idd\_snorm.f} \\\hline
--%
--{\tt idd\_enorm} & calculates the Euclidean norm of a vector &
--{\tt idd\_snorm.f} \\\hline
--%
--{\tt idd\_estrank} & estimates the numerical rank of an arbitrary
--(generally dense) matrix to a specified precision; this routine is
--randomized, and must be initialized with routine {\tt idd\_frmi} &
--{\tt iddp\_aid.f} \\\hline
--%
--{\tt idd\_frm} & transforms a vector into a vector which is
--sufficiently scrambled to be subsampled, via a composition of Rokhlin's
--random transform, random subselection, and a fast Fourier transform &
--{\tt idd\_frm.f} \\\hline
--%
--{\tt idd\_frmi} & initializes routine {\tt idd\_frm} & {\tt idd\_frm.f}
--\\\hline
--%
--{\tt idd\_getcols} & collects together selected columns of a matrix
--specified by a routine for applying the matrix to arbitrary vectors &
--{\tt idd\_id.f} \\\hline
--%
--{\tt idd\_house} & calculates the vector and scalar needed to apply the
--Householder transformation reflecting a given vector into its first
--entry & {\tt idd\_house.f} \\\hline
--%
--{\tt idd\_houseapp} & applies a Householder matrix to a vector &
--{\tt idd\_house.f} \\\hline
--%
--{\tt idd\_id2svd} & converts an approximation to a matrix in the form
--of an ID into an approximation in the form of an SVD &
--{\tt idd\_id2svd.f} \\\hline
--%
--{\tt idd\_ldiv} & finds the greatest integer less than or equal to a
--specified integer, that is divisible by another (larger) specified
--integer & {\tt idd\_sfft.f} \\\hline
--%
--{\tt idd\_pairsamps} & calculates the indices of the pairs of integers
--that the individual integers in a specified set belong to &
--{\tt idd\_frm.f} \\\hline
--%
--{\tt idd\_permmult} & multiplies together a bunch of permutations &
--{\tt idd\_qrpiv.f} \\\hline
--%
--{\tt idd\_qinqr} & reconstructs the $Q$ matrix in a $QR$ decomposition
--from the output of routines {\tt iddp\_qrpiv} or {\tt iddr\_qrpiv} &
--{\tt idd\_qrpiv.f} \\\hline
--%
--{\tt idd\_qrmatmat} & applies to multiple vectors collected together as
--a matrix the $Q$ matrix (or its transpose) in the $QR$ decomposition of
--a matrix, as described by the output of routines {\tt iddp\_qrpiv} or
--{\tt iddr\_qrpiv}; to apply $Q$ (or its transpose) to a single vector
--without having to provide a work array, use routine {\tt idd\_qrmatvec}
--instead & {\tt idd\_qrpiv.f} \\\hline
--%
--{\tt idd\_qrmatvec} & applies to a single vector the $Q$ matrix (or its
--transpose) in the $QR$ decomposition of a matrix, as described by the
--output of routines {\tt iddp\_qrpiv} or {\tt iddr\_qrpiv}; to apply $Q$ 
--(or its transpose) to several vectors efficiently, use routine
--{\tt idd\_qrmatmat} instead & {\tt idd\_qrpiv.f} \\\hline
--%
--{\tt idd\_random\_} {\tt transf} & applies rapidly a
--random orthogonal matrix to a user-supplied vector & {\tt id\_rtrans.f}
--\\\hline
--%
--{\tt idd\_random\_ transf\_init} & \raggedright initializes routines
--{\tt idd\_random\_transf} and {\tt idd\_random\_transf\_inverse} &
--{\tt id\_rtrans.f} \\\hline
--%
--{\tt idd\_random\_} {\tt transf\_inverse} & applies
--rapidly the inverse of the operator applied by routine
--{\tt idd\_random\_transf} & {\tt id\_rtrans.f} \\\hline
--%
--{\tt idd\_reconid} & reconstructs a matrix from its ID &
--{\tt idd\_id.f} \\\hline
--%
--{\tt idd\_reconint} & constructs $P$ in the ID $A = B \, P$, where the
--columns of $B$ are a subset of the columns of $A$, and $P$ is the
--projection coefficient matrix, given {\tt list}, {\tt krank}, and
--{\tt proj} output by routines {\tt iddr\_id}, {\tt iddp\_id},
--{\tt iddr\_aid}, {\tt iddp\_aid}, {\tt iddr\_rid}, or {\tt iddp\_rid} &
--{\tt idd\_id.f} \\\hline
--%
--{\tt idd\_sfft} & rapidly computes a subset of the entries of the
--discrete Fourier transform of a vector, composed with permutation
--matrices both on input and on output & {\tt idd\_sfft.f} \\\hline
--%
--{\tt idd\_sffti} & initializes routine {\tt idd\_sfft} &
--{\tt idd\_sfft.f} \\\hline
--%
--{\tt idd\_sfrm} & transforms a vector into a scrambled vector of
--specified length, via a composition of Rokhlin's random transform,
--random subselection, and a fast Fourier transform & {\tt idd\_frm.f}
--\\\hline
--%
--{\tt idd\_sfrmi} & initializes routine {\tt idd\_sfrm} &
--{\tt idd\_frm.f} \\\hline
--%
--{\tt idd\_snorm} & estimates the spectral norm of a matrix specified by
--routines for applying the matrix and its transpose to arbitrary
--vectors; this routine uses the power method with a random starting
--vector & {\tt idd\_snorm.f} \\\hline
--%
--{\tt iddp\_aid} & computes the ID of an arbitrary (generally dense)
--matrix, to a specified precision; this routine is randomized, and must
--be initialized with routine {\tt idd\_frmi} & {\tt iddp\_aid.f}
--\\\hline
--%
--{\tt iddp\_asvd} & computes the SVD of an arbitrary (generally dense)
--matrix, to a specified precision; this routine is randomized, and must
--be initialized with routine {\tt idd\_frmi} & {\tt iddp\_asvd.f}
--\\\hline
--%
--{\tt iddp\_id} & computes the ID of an arbitrary (generally dense)
--matrix, to a specified precision; this routine is often less efficient
--than routine {\tt iddp\_aid} & {\tt idd\_id.f} \\\hline
--%
--{\tt iddp\_qrpiv} & computes the pivoted $QR$ decomposition of an
--arbitrary (generally dense) matrix via Householder transformations,
--stopping at a specified precision of the decomposition &
--{\tt idd\_qrpiv.f} \\\hline
--%
--{\tt iddp\_rid} & computes the ID, to a specified precision, of a
--matrix specified by a routine for applying its transpose to arbitrary
--vectors; this routine is randomized & {\tt iddp\_rid.f} \\\hline
--%
--{\tt iddp\_rsvd} & computes the SVD, to a specified precision, of a
--matrix specified by routines for applying the matrix and its transpose
--to arbitrary vectors; this routine is randomized & {\tt iddp\_rsvd.f}
--\\\hline
--%
--{\tt iddp\_svd} & computes the SVD of an arbitrary (generally dense)
--matrix, to a specified precision; this routine is often less efficient
--than routine {\tt iddp\_asvd} & {\tt idd\_svd.f} \\\hline
--%
--{\tt iddr\_aid} & computes the ID of an arbitrary (generally dense)
--matrix, to a specified rank; this routine is randomized, and must be
--initialized by routine {\tt iddr\_aidi} & {\tt iddr\_aid.f} \\\hline
--%
--{\tt iddr\_aidi} & initializes routine {\tt iddr\_aid} &
--{\tt iddr\_aid.f} \\\hline
--%
--{\tt iddr\_asvd} & computes the SVD of an arbitrary (generally dense)
--matrix, to a specified rank; this routine is randomized, and must be
--initialized with routine {\tt idd\_aidi} & {\tt iddr\_asvd.f}
--\\\hline
--%
--{\tt iddr\_id} & computes the ID of an arbitrary (generally dense)
--matrix, to a specified rank; this routine is often less efficient than
--routine {\tt iddr\_aid} & {\tt idd\_id.f} \\\hline
--%
--{\tt iddr\_qrpiv} & computes the pivoted $QR$ decomposition of an
--arbitrary (generally dense) matrix via Householder transformations,
--stopping at a specified rank of the decomposition & {\tt idd\_qrpiv.f}
--\\\hline
--%
--{\tt iddr\_rid} & computes the ID, to a specified rank, of a matrix
--specified by a routine for applying its transpose to arbitrary vectors;
--this routine is randomized & {\tt iddr\_rid.f} \\\hline
--%
--{\tt iddr\_rsvd} & computes the SVD, to a specified rank, of a matrix
--specified by routines for applying the matrix and its transpose to
--arbitrary vectors; this routine is randomized & {\tt iddr\_rsvd.f}
--\\\hline
--%
--{\tt iddr\_svd} & computes the SVD of an arbitrary (generally dense)
--matrix, to a specified rank; this routine is often less efficient than
--routine {\tt iddr\_asvd} & {\tt idd\_svd.f} \\\hline
--%
--{\tt idz\_copycols} & collects together selected columns of a matrix &
--{\tt idz\_id.f} \\\hline
--%
--{\tt idz\_diffsnorm} & estimates the spectral norm of the difference
--between two matrices specified by routines for applying the matrices
--and their adjoints to arbitrary vectors; this routine uses the power
--method with a random starting vector & {\tt idz\_snorm.f} \\\hline
--%
--{\tt idz\_enorm} & calculates the Euclidean norm of a vector &
--{\tt idz\_snorm.f} \\\hline
--%
--{\tt idz\_estrank} & estimates the numerical rank of an arbitrary
--(generally dense) matrix to a specified precision; this routine is
--randomized, and must be initialized with routine {\tt idz\_frmi} &
--{\tt idzp\_aid.f} \\\hline
--%
--{\tt idz\_frm} & transforms a vector into a vector which is
--sufficiently scrambled to be subsampled, via a composition of Rokhlin's
--random transform, random subselection, and a fast Fourier transform &
--{\tt idz\_frm.f} \\\hline
--%
--{\tt idz\_frmi} & initializes routine {\tt idz\_frm} & {\tt idz\_frm.f}
--\\\hline
--%
--{\tt idz\_getcols} & collects together selected columns of a matrix
--specified by a routine for applying the matrix to arbitrary vectors &
--{\tt idz\_id.f} \\\hline
--%
--{\tt idz\_house} & calculates the vector and scalar needed to apply the
--Householder transformation reflecting a given vector into its first
--entry & {\tt idz\_house.f} \\\hline
--%
--{\tt idz\_houseapp} & applies a Householder matrix to a vector &
--{\tt idz\_house.f} \\\hline
--%
--{\tt idz\_id2svd} & converts an approximation to a matrix in the form
--of an ID into an approximation in the form of an SVD &
--{\tt idz\_id2svd.f} \\\hline
--%
--{\tt idz\_ldiv} & finds the greatest integer less than or equal to a
--specified integer, that is divisible by another (larger) specified
--integer & {\tt idz\_sfft.f} \\\hline
--%
--{\tt idz\_permmult} & multiplies together a bunch of permutations &
--{\tt idz\_qrpiv.f} \\\hline
--%
--{\tt idz\_qinqr} & reconstructs the $Q$ matrix in a $QR$ decomposition
--from the output of routines {\tt idzp\_qrpiv} or {\tt idzr\_qrpiv} &
--{\tt idz\_qrpiv.f} \\\hline
--%
--{\tt idz\_qrmatmat} & applies to multiple vectors collected together as
--a matrix the $Q$ matrix (or its adjoint) in the $QR$ decomposition of
--a matrix, as described by the output of routines {\tt idzp\_qrpiv} or
--{\tt idzr\_qrpiv}; to apply $Q$ (or its adjoint) to a single vector
--without having to provide a work array, use routine {\tt idz\_qrmatvec}
--instead & {\tt idz\_qrpiv.f} \\\hline
--%
--{\tt idz\_qrmatvec} & applies to a single vector the $Q$ matrix (or its
--adjoint) in the $QR$ decomposition of a matrix, as described by the
--output of routines {\tt idzp\_qrpiv} or {\tt idzr\_qrpiv}; to apply $Q$ 
--(or its adjoint) to several vectors efficiently, use routine
--{\tt idz\_qrmatmat} instead & {\tt idz\_qrpiv.f} \\\hline
--%
--{\tt idz\_random\_ transf} & applies rapidly a random unitary matrix to
--a user-supplied vector & {\tt id\_rtrans.f} \\\hline
--%
--{\tt idz\_random\_ transf\_init} & \raggedright initializes routines
--{\tt idz\_random\_transf} and {\tt idz\_random\_transf\_inverse} &
--{\tt id\_rtrans.f} \\\hline
--%
--{\tt idz\_random\_ transf\_inverse} & applies rapidly the inverse of
--the operator applied by routine {\tt idz\_random\_transf} &
--{\tt id\_rtrans.f} \\\hline
--%
--{\tt idz\_reconid} & reconstructs a matrix from its ID &
--{\tt idz\_id.f} \\\hline
--%
--{\tt idz\_reconint} & constructs $P$ in the ID $A = B \, P$, where the
--columns of $B$ are a subset of the columns of $A$, and $P$ is the
--projection coefficient matrix, given {\tt list}, {\tt krank}, and
--{\tt proj} output by routines {\tt idzr\_id}, {\tt idzp\_id},
--{\tt idzr\_aid}, {\tt idzp\_aid}, {\tt idzr\_rid}, or {\tt idzp\_rid} &
--{\tt idz\_id.f} \\\hline
--%
--{\tt idz\_sfft} & rapidly computes a subset of the entries of the
--discrete Fourier transform of a vector, composed with permutation
--matrices both on input and on output & {\tt idz\_sfft.f} \\\hline
--%
--{\tt idz\_sffti} & initializes routine {\tt idz\_sfft} &
--{\tt idz\_sfft.f} \\\hline
--%
--{\tt idz\_sfrm} & transforms a vector into a scrambled vector of
--specified length, via a composition of Rokhlin's random transform,
--random subselection, and a fast Fourier transform & {\tt idz\_frm.f}
--\\\hline
--%
--{\tt idz\_sfrmi} & initializes routine {\tt idz\_sfrm} &
--{\tt idz\_frm.f} \\\hline
--%
--{\tt idz\_snorm} & estimates the spectral norm of a matrix specified by
--routines for applying the matrix and its adjoint to arbitrary
--vectors; this routine uses the power method with a random starting
--vector & {\tt idz\_snorm.f} \\\hline
--%
--{\tt idzp\_aid} & computes the ID of an arbitrary (generally dense)
--matrix, to a specified precision; this routine is randomized, and must
--be initialized with routine {\tt idz\_frmi} & {\tt idzp\_aid.f}
--\\\hline
--%
--{\tt idzp\_asvd} & computes the SVD of an arbitrary (generally dense)
--matrix, to a specified precision; this routine is randomized, and must
--be initialized with routine {\tt idz\_frmi} & {\tt idzp\_asvd.f}
--\\\hline
--%
--{\tt idzp\_id} & computes the ID of an arbitrary (generally dense)
--matrix, to a specified precision; this routine is often less efficient
--than routine {\tt idzp\_aid} & {\tt idz\_id.f} \\\hline
--%
--{\tt idzp\_qrpiv} & computes the pivoted $QR$ decomposition of an
--arbitrary (generally dense) matrix via Householder transformations,
--stopping at a specified precision of the decomposition &
--{\tt idz\_qrpiv.f} \\\hline
--%
--{\tt idzp\_rid} & computes the ID, to a specified precision, of a
--matrix specified by a routine for applying its adjoint to arbitrary
--vectors; this routine is randomized & {\tt idzp\_rid.f} \\\hline
--%
--{\tt idzp\_rsvd} & computes the SVD, to a specified precision, of a
--matrix specified by routines for applying the matrix and its adjoint
--to arbitrary vectors; this routine is randomized & {\tt idzp\_rsvd.f}
--\\\hline
--%
--{\tt idzp\_svd} & computes the SVD of an arbitrary (generally dense)
--matrix, to a specified precision; this routine is often less efficient
--than routine {\tt idzp\_asvd} & {\tt idz\_svd.f} \\\hline
--%
--{\tt idzr\_aid} & computes the ID of an arbitrary (generally dense)
--matrix, to a specified rank; this routine is randomized, and must be
--initialized by routine {\tt idzr\_aidi} & {\tt idzr\_aid.f} \\\hline
--%
--{\tt idzr\_aidi} & initializes routine {\tt idzr\_aid} &
--{\tt idzr\_aid.f} \\\hline
--%
--{\tt idzr\_asvd} & computes the SVD of an arbitrary (generally dense)
--matrix, to a specified rank; this routine is randomized, and must be
--initialized with routine {\tt idz\_aidi} & {\tt idzr\_asvd.f}
--\\\hline
--%
--{\tt idzr\_id} & computes the ID of an arbitrary (generally dense)
--matrix, to a specified rank; this routine is often less efficient than
--routine {\tt idzr\_aid} & {\tt idz\_id.f} \\\hline
--%
--{\tt idzr\_qrpiv} & computes the pivoted $QR$ decomposition of an
--arbitrary (generally dense) matrix via Householder transformations,
--stopping at a specified rank of the decomposition & {\tt idz\_qrpiv.f}
--\\\hline
--%
--{\tt idzr\_rid} & computes the ID, to a specified rank, of a matrix
--specified by a routine for applying its adjoint to arbitrary vectors;
--this routine is randomized & {\tt idzr\_rid.f} \\\hline
--%
--{\tt idzr\_rsvd} & computes the SVD, to a specified rank, of a matrix
--specified by routines for applying the matrix and its adjoint to
--arbitrary vectors; this routine is randomized & {\tt idzr\_rsvd.f}
--\\\hline
--%
--{\tt idzr\_svd} & computes the SVD of an arbitrary (generally dense)
--matrix, to a specified rank; this routine is often less efficient than
--routine {\tt idzr\_asvd} & {\tt idz\_svd.f} \\
--%
--\end{supertabular}
--\end{center}
--
--
--
--\section{Documentation in the source codes}
--
--Each routine in the source codes includes documentation
--in the comments immediately following the declaration
--of the subroutine's calling sequence.
--This documentation describes the purpose of the routine,
--the input and output variables, and the required work arrays (if any). 
--This documentation also cites relevant references.
--Please pay attention to the {\it N.B.}'s;
--{\it N.B.} stands for {\it nota bene} (Latin for ``note well'')
--and highlights important information about the routines.
--
--
--
--\section{Notation and decompositions}
--\label{defs}
--
--This section sets notational conventions employed
--in this documentation and the associated software,
--and defines both the singular value decomposition (SVD)
--and the interpolative decomposition (ID).
--For information concerning other mathematical objects
--used in the code (such as Householder transformations,
--pivoted $QR$ decompositions, and discrete and fast Fourier transforms
----- DFTs and FFTs), see, for example,~\cite{golub-van_loan}.
--For detailed descriptions and proofs of the mathematical facts
--discussed in the present section, see, for example,
--\cite{golub-van_loan} and the references
--in~\cite{halko-martinsson-tropp}.
--
--Throughout this document and the accompanying software distribution,
--$\| \x \|$ always denotes the Euclidean norm of the vector $\x$,
--and $\| A \|$ always denotes the spectral norm of the matrix $A$.
--Subsection~\ref{Euclidean} below defines the Euclidean norm;
--Subsection~\ref{spectral} below defines the spectral norm.
--We use $A^*$ to denote the adjoint of the matrix $A$.
--
--
--\subsection{Euclidean norm}
--\label{Euclidean}
--
--For any positive integer $n$, and vector $\x$ of length $n$,
--the Euclidean ($l^2$) norm $\| \x \|$ is
--%
--\begin{equation}
--\| \x \| = \sqrt{ \sum_{k=1}^n |x_k|^2 },
--\end{equation}
--%
--where $x_1$,~$x_2$, \dots, $x_{n-1}$,~$x_n$ are the entries of $\x$.
--
--
--\subsection{Spectral norm}
--\label{spectral}
--
--For any positive integers $m$ and $n$, and $m \times n$ matrix $A$,
--the spectral ($l^2$ operator) norm $\| A \|$ is
--%
--\begin{equation}
--\| A_{m \times n} \|
--= \max \frac{\| A_{m \times n} \, \x_{n \times 1} \|}
--            {\| \x_{n \times 1} \|},
--\end{equation}
--%
--where the $\max$ is taken over all $n \times 1$ column vectors $\x$
--such that $\| \x \| \ne 0$.
--
--
--\subsection{Singular value decomposition (SVD)}
--
--For any positive real number $\epsilon$,
--positive integers $k$, $m$, and $n$ with $k \le m$ and $k \le n$,
--and any $m \times n$ matrix $A$,
--a rank-$k$ approximation to $A$ in the form of an SVD
--(to precision $\epsilon$) consists of an $m \times k$ matrix $U$
--whose columns are orthonormal, an $n \times k$ matrix $V$
--whose columns are orthonormal, and a diagonal $k \times k$ matrix
--$\Sigma$ with diagonal entries
--$\Sigma_{1,1} \ge \Sigma_{2,2} \ge \dots \ge \Sigma_{n-1,n-1}
--                                         \ge \Sigma_{n,n} \ge 0$,
--such that
--%
--\begin{equation}
--\| A_{m \times n} - U_{m \times k} \, \Sigma_{k \times k}
--                 \, (V^*)_{k \times n} \| \le \epsilon.
--\end{equation}
--%
--The product $U \, \Sigma \, V^*$ is known as an SVD.
--The columns of $U$ are known as left singular vectors;
--the columns of $V$ are known as right singular vectors.
--The diagonal entries of $\Sigma$ are known as singular values.
--
--When $k = m$ or $k = n$, and $A = U \, \Sigma \, V^*$,
--then $U \, \Sigma \, V^*$ is known as the SVD
--of $A$; the columns of $U$ are the left singular vectors of $A$,
--the columns of $V$ are the right singular vectors of $A$,
--and the diagonal entries of $\Sigma$ are the singular values of $A$.
--For any positive integer $k$ with $k < m$ and $k < n$,
--there exists a rank-$k$ approximation to $A$ in the form of an SVD,
--to precision $\sigma_{k+1}$, where $\sigma_{k+1}$ is the $(k+1)^\st$
--greatest singular value of $A$.
--
--
--\subsection{Interpolative decomposition (ID)}
--
--For any positive real number $\epsilon$,
--positive integers $k$, $m$, and $n$ with $k \le m$ and $k \le n$,
--and any $m \times n$ matrix $A$,
--a rank-$k$ approximation to $A$ in the form of an ID
--(to precision $\epsilon$) consists of a $k \times n$ matrix $P$,
--and an $m \times k$ matrix $B$ whose columns constitute a subset
--of the columns of $A$, such that
--%
--\begin{enumerate}
--\item $\| A_{m \times n} - B_{m \times k} \, P_{k \times n} \|
--      \le \epsilon$,
--\item some subset of the columns of $P$ makes up the $k \times k$
--      identity matrix, and
--\item every entry of $P$ has an absolute value less than or equal
--      to a reasonably small positive real number, say 2.
--\end{enumerate}
--%
--The product $B \, P$ is known as an ID.
--The matrix $P$ is known as the projection or interpolation matrix
--of the ID. Property~1 above approximates each column of $A$
--via a linear combination of the columns of $B$
--(which are themselves columns of $A$), with the coefficients
--in the linear combination given by the entries of $P$.
--
--The interpolative decomposition is ``interpolative''
--due to Property~2 above. The ID is numerically stable
--due to Property~3 above.
--It follows from Property~2 that the least ($k^\th$ greatest) singular value
--of $P$ is at least 1. Combining Properties~2 and~3 yields that
--%
--\begin{equation}
--\| P_{k \times n} \| \le \sqrt{4k(n-k)+1}.
--\end{equation}
--
--When $k = m$ or $k = n$, and $A = B \, P$,
--then $B \, P$ is known as the ID of $A$.
--For any positive integer $k$ with $k < m$ and $k < n$,
--there exists a rank-$k$ approximation to $A$ in the form of an ID,
--to precision $\sqrt{k(n-k)+1} \; \sigma_{k+1}$,
--where $\sigma_{k+1}$ is the $(k+1)^\st$ greatest singular value of $A$
--(in fact, there exists an ID in which every entry
--of the projection matrix $P$ has an absolute value less than or equal
--to 1).
--
--
--
--\section{Bug reports, feedback, and support}
--
--Please let us know about errors in the software or in the documentation
--via e-mail to {\tt tygert@aya.yale.edu}.
--We would also appreciate hearing about particular applications of the codes,
--especially in the form of journal articles
--e-mailed to {\tt tygert@aya.yale.edu}.
--Mathematical and technical support may also be available via e-mail. Enjoy!
--
--
--
--\bibliographystyle{siam}
--\bibliography{doc}
--
--
--\end{document}
-diff --git a/scipy/linalg/src/id_dist/doc/supertabular.sty b/scipy/linalg/src/id_dist/doc/supertabular.sty
-deleted file mode 100644
-index ac2638c23..000000000
---- a/scipy/linalg/src/id_dist/doc/supertabular.sty
-+++ /dev/null
-@@ -1,483 +0,0 @@
--%%
--%% This is file `supertabular.sty',
--%% generated with the docstrip utility.
--%%
--%% The original source files were:
--%%
--%% supertabular.dtx  (with options: `package')
--%% Copyright (C) 1989-2004 Johannes Braams. All rights reserved.
--%% 
--%% This file was generated from file(s) of the supertabular package.
--%% -----------------------------------------------------------------
--%% 
--%% It may be distributed and/or modified under the
--%% conditions of the LaTeX Project Public License, either version 1.3
--%% of this license or (at your option) any later version.
--%% The latest version of this license is in
--%%   http://www.latex-project.org/lppl.txt
--%% and version 1.3 or later is part of all distributions of LaTeX
--%% version 2003/12/01 or later.
--%% 
--%% This work has the LPPL maintenance status "maintained".
--%% 
--%% The Current Maintainer of this work is Johannes Braams.
--%% 
--%% This file may only be distributed together with a copy of the
--%% supertabular package. You may however distribute the supertabular package
--%% without such generated files.
--%% 
--%% The list of all files belonging to the supertabular package is
--%% given in the file `manifest.txt.
--%% 
--%% The list of derived (unpacked) files belonging to the distribution
--%% and covered by LPPL is defined by the unpacking scripts (with
--%% extension .ins) which are part of the distribution.
--%% Sourcefile `supertabular.dtx'.
--%%
--%% Copyright (C) 1988 by Theo Jurriens
--%% Copyright (C) 1990-2004 by Johannes Braams texniek at braams.cistron.nl
--%%                            Kersengaarde 33
--%%                            2723 BP Zoetermeer NL
--%%                       all rights reserved.
--%%
--%%
--\NeedsTeXFormat{LaTeX2e}
--\ProvidesPackage{supertabular}
--              [2004/02/20 v4.1e the supertabular environment]
--\newcount\c@tracingst
--\DeclareOption{errorshow}{\c@tracingst\z@}
--\DeclareOption{pageshow}{\c@tracingst\tw@}
--\DeclareOption{debugshow}{\c@tracingst5\relax}
--\ProcessOptions
--\newif\if@topcaption \@topcaptiontrue
--\def\topcaption{\@topcaptiontrue\tablecaption}
--\def\bottomcaption{\@topcaptionfalse\tablecaption}
--\long\def\tablecaption{%
--  \refstepcounter{table}\@dblarg{\@xtablecaption}}
--\long\def\@xtablecaption[#1]#2{%
--  \long\gdef\@process@tablecaption{\ST@caption{table}[#1]{#2}}}
--\global\let\@process@tablecaption\relax
--\newif\ifST@star
--\newif\ifST@mp
--\newdimen\ST@wd
--\newskip\ST@rightskip
--\newskip\ST@leftskip
--\newskip\ST@parfillskip
--\long\def\ST@caption#1[#2]#3{\par%
--  \addcontentsline{\csname ext@#1\endcsname}{#1}%
--                  {\protect\numberline{%
--                      \csname the#1\endcsname}{\ignorespaces #2}}
--  \begingroup
--    \@parboxrestore
--    \normalsize
--    \if@topcaption \vskip -10\p@ \fi
--    \@makecaption{\csname fnum@#1\endcsname}{\ignorespaces #3}\par
--    \if@topcaption \vskip 10\p@ \fi
--  \endgroup}
--\newcommand\tablehead[1]{%
--  \gdef\@tablehead{%
--  \noalign{%
--      \global\let\@savcr=\\
--      \global\let\\=\org@tabularcr}%
--    #1%
--    \noalign{\global\let\\=\@savcr}}}
--\tablehead{}
--\newcommand\tablefirsthead[1]{\gdef\@table@first@head{#1}}
--\newcommand\tabletail[1]{%
--  \gdef\@tabletail{%
--    \noalign{%
--      \global\let\@savcr=\\
--      \global\let\\=\org@tabularcr}%
--    #1%
--    \noalign{\global\let\\=\@savcr}}}
--\tabletail{}
--\newcommand\tablelasttail[1]{\gdef\@table@last@tail{#1}}
--\newcommand\sttraceon{\c@tracingst5\relax}
--\newcommand\sttraceoff{\c@tracingst\z@}
--\newcommand\ST@trace[2]{%
--  \ifnum\c@tracingst>#1\relax
--    \GenericWarning
--      {(supertabular)\@spaces\@spaces}
--      {Package supertabular: #2}%
--  \fi
--  }
--\newdimen\ST@pageleft
--\newcommand*\shrinkheight[1]{%
--  \noalign{\global\advance\ST@pageleft-#1\relax}}
--\newcommand*\setSTheight[1]{%
--  \noalign{\global\ST@pageleft=#1\relax}}
--\newdimen\ST@headht
--\newdimen\ST@tailht
--\newdimen\ST@pagesofar
--\newdimen\ST@pboxht
--\newdimen\ST@lineht
--\newdimen\ST@stretchht
--\newdimen\ST@prevht
--\newdimen\ST@toadd
--\newdimen\ST@dimen
--\newbox\ST@pbox
--\def\ST@tabularcr{%
--  {\ifnum0=`}\fi
--  \@ifstar{\ST@xtabularcr}{\ST@xtabularcr}}
--\def\ST@xtabularcr{%
--  \@ifnextchar[%]
--    {\ST@argtabularcr}%
--    {\ifnum0=`{\fi}\cr\ST@cr}}
--\def\ST@argtabularcr[#1]{%
--  \ifnum0=`{\fi}%
--  \ifdim #1>\z@
--    \unskip\ST@xargarraycr{#1}
--  \else
--    \ST@yargarraycr{#1}%
--  \fi}
--\def\ST@xargarraycr#1{%
--  \@tempdima #1\advance\@tempdima \dp \@arstrutbox
--  \vrule \@height\z@ \@depth\@tempdima \@width\z@ \cr
--  \noalign{\global\ST@toadd=#1}\ST@cr}
--\def\ST@yargarraycr#1{%
--  \cr\noalign{\vskip #1\global\ST@toadd=#1}\ST@cr}
--\def\ST@startpbox#1{%
--  \setbox\ST@pbox\vtop\bgroup\hsize#1\@arrayparboxrestore}
--\def\ST@astartpbox#1{%
--  \bgroup\hsize#1%
--  \setbox\ST@pbox\vtop\bgroup\hsize#1\@arrayparboxrestore}
--\def\ST@endpbox{%
--  \@finalstrut\@arstrutbox\par\egroup
--  \ST@dimen=\ht\ST@pbox
--  \advance\ST@dimen by \dp\ST@pbox
--  \ifnum\ST@pboxht<\ST@dimen
--    \global\ST@pboxht=\ST@dimen
--  \fi
--  \ST@dimen=\z@
--  \box\ST@pbox\hfil}
--\def\ST@aendpbox{%
--  \@finalstrut\@arstrutbox\par\egroup
--  \ST@dimen=\ht\ST@pbox
--  \advance\ST@dimen by \dp\ST@pbox
--  \ifnum\ST@pboxht<\ST@dimen
--    \global\ST@pboxht=\ST@dimen
--  \fi
--  \ST@dimen=\z@
--  \unvbox\ST@pbox\egroup\hfil}
--\def\estimate@lineht{%
--  \ST@lineht=\arraystretch \baslineskp
--  \global\advance\ST@lineht by 1\p@
--  \ST@stretchht\ST@lineht\advance\ST@stretchht-\baslineskp
--  \ifdim\ST@stretchht<\z@\ST@stretchht\z@\fi
--  \ST@trace\tw@{Average line height: \the\ST@lineht}%
--  \ST@trace\tw@{Stretched line height: \the\ST@stretchht}%
--  }
--\def\@calfirstpageht{%
--  \ST@trace\tw@{Calculating height of tabular on first page}%
--  \global\ST@pagesofar\pagetotal
--  \global\ST@pageleft\@colroom
--  \ST@trace\tw@{Height of text = \the\pagetotal; \MessageBreak
--                Height of page = \the\ST@pageleft}%
--  \if@twocolumn
--    \ST@trace\tw@{two column mode}%
--    \if@firstcolumn
--     \ST@trace\tw@{First column}%
--      \ifnum\ST@pagesofar > \ST@pageleft
--        \global\ST@pageleft=2\ST@pageleft
--        \ifnum\ST@pagesofar > \ST@pageleft
--          \newpage\@calnextpageht
--          \ST@trace\tw@{starting new page}%
--        \else
--          \ST@trace\tw@{Second column}%
--          \global\advance\ST@pageleft -\ST@pagesofar
--          \global\advance\ST@pageleft -\@colroom
--        \fi
--      \else
--        \global\advance\ST@pageleft by -\ST@pagesofar
--        \global\ST@pagesofar\z@
--      \fi
--    \else
--      \ST@trace\tw@{Second column}
--      \ifnum\ST@pagesofar > \ST@pageleft
--        \ST@trace\tw@{starting new page}%
--        \newpage\@calnextpageht
--      \else
--        \global\advance\ST@pageleft by -\ST@pagesofar
--        \global\ST@pagesofar\z@
--      \fi
--    \fi
--  \else
--    \ST@trace\tw@{one column mode}%
--    \ifnum\ST@pagesofar > \ST@pageleft
--      \ST@trace\tw@{starting new page}%
--      \newpage\@calnextpageht
--    \else
--      \global\advance\ST@pageleft by -\ST@pagesofar
--      \global\ST@pagesofar\z@
--    \fi
--  \fi
--  \ST@trace\tw@{Available height: \the\ST@pageleft}%
--  \ifx\@@tablehead\@empty
--    \ST@headht=\z@
--  \else
--    \setbox\@tempboxa=\vbox{\@arrayparboxrestore
--      \ST@restore
--      \expandafter\tabular\expandafter{\ST@tableformat}%
--      \@@tablehead\endtabular}%
--    \ST@headht=\ht\@tempboxa\advance\ST@headht\dp\@tempboxa
--  \fi
--  \ST@trace\tw@{Height of head: \the\ST@headht}%
--  \ifx\@tabletail\@empty
--    \ST@tailht=\z@
--  \else
--    \setbox\@tempboxa=\vbox{\@arrayparboxrestore
--      \ST@restore
--      \expandafter\tabular\expandafter{\ST@tableformat}
--        \@tabletail\endtabular}
--    \ST@tailht=\ht\@tempboxa\advance\ST@tailht\dp\@tempboxa
--  \fi
--  \advance\ST@tailht by \ST@lineht
--  \ST@trace\tw@{Height of tail: \the\ST@tailht}%
--  \ST@trace\tw@{Maximum height of tabular: \the\ST@pageleft}%
--  \@tempdima\ST@headht
--  \advance\@tempdima\ST@lineht
--  \advance\@tempdima\ST@tailht
--  \ST@trace\tw@{Minimum height of tabular: \the\@tempdima}%
--  \ifnum\@tempdima>\ST@pageleft
--    \ST@trace\tw@{starting new page}%
--    \newpage\@calnextpageht
--  \fi
--}
--\def\@calnextpageht{%
--  \ST@trace\tw@{Calculating height of tabular on next page}%
--  \global\ST@pageleft\@colroom
--  \global\ST@pagesofar=\z@
--  \ST@trace\tw@{Maximum height of tabular: \the\ST@pageleft}%
--  }
--\def\x@supertabular{%
--  \let\org@tabular\tabular
--  \let\tabular\inner@tabular
--  \expandafter\let
--    \csname org@tabular*\expandafter\endcsname
--    \csname tabular*\endcsname
--  \expandafter\let\csname tabular*\expandafter\endcsname
--    \csname inner@tabular*\endcsname
--  \if@topcaption \@process@tablecaption \fi
--  \global\let\@oldcr=\\
--  \def\baslineskp{\baselineskip}%
--  \ifx\undefined\@classix
--    \let\org@tabularcr\@tabularcr
--    \let\@tabularcr\ST@tabularcr
--    \let\org@startpbox=\@startpbox
--    \let\org@endpbox=\@endpbox
--    \let\@@startpbox=\ST@startpbox
--    \let\@@endpbox=\ST@endpbox
--  \else
--    \let\org@tabularcr\@arraycr
--    \let\@arraycr\ST@tabularcr
--    \let\org@startpbox=\@startpbox
--    \let\org@endpbox=\@endpbox
--    \let\@startpbox=\ST@astartpbox
--    \let\@endpbox=\ST@aendpbox
--  \fi
--  \ifx\@table@first@head\undefined
--    \let\@@tablehead=\@tablehead
--  \else
--    \let\@@tablehead=\@table@first@head
--  \fi
--  \let\ST@skippage\ST@skipfirstpart
--  \estimate@lineht
--  \@calfirstpageht
--  \noindent
--  }
--\def\supertabular{%
--  \@ifnextchar[{\@supertabular}%]
--               {\@supertabular[]}}
--\def\@supertabular[#1]#2{%
--  \def\ST@tableformat{#2}%
--  \ST@trace\tw@{Starting a new supertabular}%
--  \global\ST@starfalse
--  \global\ST@mpfalse
--  \x@supertabular
--  \expandafter\org@tabular\expandafter{\ST@tableformat}%
--  \@@tablehead}
--\@namedef{supertabular*}#1{%
--  \@ifnextchar[{\@nameuse{@supertabular*}{#1}}%
--               {\@nameuse{@supertabular*}{#1}[]}%]
--  }
--\@namedef{@supertabular*}#1[#2]#3{%
--  \ST@trace\tw@{Starting a new supertabular*}%
--  \def\ST@tableformat{#3}%
--  \ST@wd=#1\relax
--  \global\ST@startrue
--  \global\ST@mpfalse
--  \x@supertabular
--  \expandafter\csname org@tabular*\expandafter\endcsname
--  \expandafter{\expandafter\ST@wd\expandafter}%
--  \expandafter{\ST@tableformat}%
--  \@@tablehead}%
--\def\mpsupertabular{%
--  \@ifnextchar[{\@mpsupertabular}%]
--               {\@mpsupertabular[]}}
--\def\@mpsupertabular[#1]#2{%
--  \def\ST@tableformat{#2}%
--  \ST@trace\tw@{Starting a new mpsupertabular}%
--  \global\ST@starfalse
--  \global\ST@mptrue
--  \ST@rightskip \rightskip
--  \ST@leftskip \leftskip
--  \ST@parfillskip \parfillskip
--  \x@supertabular
--  \minipage{\columnwidth}%
--  \parfillskip\ST@parfillskip
--  \rightskip \ST@rightskip
--  \leftskip \ST@leftskip
--  \noindent\expandafter\org@tabular\expandafter{\ST@tableformat}%
--  \@@tablehead}
--\@namedef{mpsupertabular*}#1{%
--  \@ifnextchar[{\@nameuse{@mpsupertabular*}{#1}}%
--               {\@nameuse{@mpsupertabular*}{#1}[]}%]
--  }
--\@namedef{@mpsupertabular*}#1[#2]#3{%
--  \ST@trace\tw@{Starting a new mpsupertabular*}%
--  \def\ST@tableformat{#3}%
--  \ST@wd=#1\relax
--  \global\ST@startrue
--  \global\ST@mptrue
--  \ST@rightskip \rightskip
--  \ST@leftskip \leftskip
--  \ST@parfillskip \parfillskip
--  \x@supertabular
--  \minipage{\columnwidth}%
--  \parfillskip\ST@parfillskip
--  \rightskip \ST@rightskip
--  \leftskip \ST@leftskip
--  \noindent\expandafter\csname org@tabular*\expandafter\endcsname
--  \expandafter{\expandafter\ST@wd\expandafter}%
--  \expandafter{\ST@tableformat}%
--  \@@tablehead}%
--\def\endsupertabular{%
--  \ifx\@table@last@tail\undefined
--    \@tabletail
--  \else
--    \@table@last@tail
--  \fi
--  \csname endtabular\ifST@star*\fi\endcsname
--  \ST@restore
--  \if@topcaption
--  \else
--    \@process@tablecaption
--    \@topcaptiontrue
--  \fi
--  \global\let\\\@oldcr
--  \global\let\@process@tablecaption\relax
--  \ST@trace\tw@{Ended a supertabular\ifST@star*\fi}%
--  }
--\expandafter\let\csname endsupertabular*\endcsname\endsupertabular
--\def\endmpsupertabular{%
--  \ifx\@table@last@tail\undefined
--    \@tabletail
--  \else
--    \@table@last@tail
--  \fi
--  \csname endtabular\ifST@star*\fi\endcsname
--  \endminipage
--  \ST@restore
--  \if@topcaption
--  \else
--    \@process@tablecaption
--    \@topcaptiontrue
--  \fi
--  \global\let\\\@oldcr
--  \global\let\@process@tablecaption\relax
--  \ST@trace\tw@{Ended a mpsupertabular\ifST@star*\fi}%
--  }
--\expandafter\let\csname endmpsupertabular*\endcsname\endmpsupertabular
--\def\ST@restore{%
--  \ifx\undefined\@classix
--    \let\@tabularcr\org@tabularcr
--  \else
--    \let\@arraycr\org@tabularcr
--  \fi
--  \let\@startpbox\org@startpbox
--  \let\@endpbox\org@endpbox
--  }
--\def\inner@tabular{%
--  \ST@restore
--  \let\\\@oldcr
--  \noindent
--  \org@tabular}
--\@namedef{inner@tabular*}{%
--  \ST@restore
--  \let\\\@oldcr
--  \noindent
--  \csname org@tabular*\endcsname}
--\def\ST@cr{%
--  \noalign{%
--    \ifnum\ST@pboxht<\ST@lineht
--      \global\advance\ST@pageleft -\ST@lineht
--      \global\ST@prevht\ST@lineht
--    \else
--     \ST@trace\thr@@{Added par box with height \the\ST@pboxht}%
--      \global\advance\ST@pageleft -\ST@pboxht
--      \global\advance\ST@pageleft -0.1\ST@pboxht
--      \global\advance\ST@pageleft -\ST@stretchht
--      \global\ST@prevht\ST@pboxht
--      \global\ST@pboxht\z@
--    \fi
--    \global\advance\ST@pageleft -\ST@toadd
--    \global\ST@toadd=\z@
--    \ST@trace\thr@@{Space left for tabular: \the\ST@pageleft}%
--  }
--  \noalign{\global\let\ST@next\@empty}%
--  \ifnum\ST@pageleft<\z@
--    \ST@skippage
--  \else
--    \noalign{\global\@tempdima\ST@tailht
--      \global\advance\@tempdima\ST@prevht
--    \ifST@mp
--      \ifvoid\@mpfootins\else
--        \global\advance\@tempdima\ht\@mpfootins
--        \global\advance\@tempdima 3pt
--      \fi
--    \fi}
--    \ifnum\ST@pageleft<\@tempdima
--      \ST@newpage
--    \fi
--  \fi
--  \ST@next}
--\def\ST@skipfirstpart{%
--  \noalign{%
--    \ST@trace\tw@{Tabular too high, moving to next page}%
--    \global\advance\ST@pageleft\pagetotal
--    \global\ST@pagesofar\z@
--    \newpage
--    \global\let\ST@skippage\ST@newpage
--    }}
--\def\ST@newpage{%
--  \noalign{\ST@trace\tw@{Starting new page, writing tail}}%
--  \@tabletail
--  \ifST@star
--    \csname endtabular*\endcsname
--  \else
--    \endtabular
--  \fi
--  \ifST@mp
--    \endminipage
--  \fi
--  \global\let\ST@skippage\ST@newpage
--  \newpage\@calnextpageht
--  \let\ST@next\@tablehead
--  \ST@trace\tw@{writing head}%
--  \ifST@mp
--    \noindent\minipage{\columnwidth}%
--    \parfillskip\ST@parfillskip
--    \rightskip \ST@rightskip
--    \leftskip \ST@leftskip
--  \fi
--  \noindent
--  \ifST@star
--    \expandafter\csname org@tabular*\expandafter\endcsname
--    \expandafter{\expandafter\ST@wd\expandafter}%
--    \expandafter{\ST@tableformat}%
--  \else
--    \expandafter\org@tabular\expandafter{\ST@tableformat}%
--  \fi}
--\endinput
--%%
--%% End of file `supertabular.sty'.
-diff --git a/scipy/linalg/src/id_dist/src/dfft.f b/scipy/linalg/src/id_dist/src/dfft.f
-deleted file mode 100644
-index b1b1b3206..000000000
---- a/scipy/linalg/src/id_dist/src/dfft.f
-+++ /dev/null
-@@ -1,3014 +0,0 @@
--C
--C                       FFTPACK
--C
--C * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
--C
--C                   VERSION 4  APRIL 1985
--C
--C      A PACKAGE OF FORTRAN SUBPROGRAMS FOR THE FAST FOURIER
--C       TRANSFORM OF PERIODIC AND OTHER SYMMETRIC SEQUENCES
--C
--C                          BY
--C
--C                   PAUL N SWARZTRAUBER
--C
--C   NATIONAL CENTER FOR ATMOSPHERIC RESEARCH  BOULDER,COLORADO 80307
--C
--C    WHICH IS SPONSORED BY THE NATIONAL SCIENCE FOUNDATION
--C
--C * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
--C
--C
--C THIS PACKAGE CONSISTS OF PROGRAMS WHICH PERFORM FAST FOURIER
--C TRANSFORMS FOR BOTH COMPLEX AND REAL PERIODIC SEQUENCES AND
--C CERTAIN OTHER SYMMETRIC SEQUENCES THAT ARE LISTED BELOW.
--C
--C 1.   DFFTI     INITIALIZE  DFFTF AND DFFTB
--C 2.   DFFTF     FORWARD TRANSFORM OF A REAL PERIODIC SEQUENCE
--C 3.   DFFTB     BACKWARD TRANSFORM OF A REAL COEFFICIENT ARRAY
--C
--C 4.   DZFFTI    INITIALIZE DZFFTF AND DZFFTB
--C 5.   DZFFTF    A SIMPLIFIED REAL PERIODIC FORWARD TRANSFORM
--C 6.   DZFFTB    A SIMPLIFIED REAL PERIODIC BACKWARD TRANSFORM
--C
--C 7.   DSINTI     INITIALIZE DSINT
--C 8.   DSINT      SINE TRANSFORM OF A REAL ODD SEQUENCE
--C
--C 9.   DCOSTI     INITIALIZE DCOST
--C 10.  DCOST      COSINE TRANSFORM OF A REAL EVEN SEQUENCE
--C
--C 11.  DSINQI     INITIALIZE DSINQF AND DSINQB
--C 12.  DSINQF     FORWARD SINE TRANSFORM WITH ODD WAVE NUMBERS
--C 13.  DSINQB     UNNORMALIZED INVERSE OF DSINQF
--C
--C 14.  DCOSQI     INITIALIZE DCOSQF AND DCOSQB
--C 15.  DCOSQF     FORWARD COSINE TRANSFORM WITH ODD WAVE NUMBERS
--C 16.  DCOSQB     UNNORMALIZED INVERSE OF DCOSQF
--C
--C 17.  ZFFTI     INITIALIZE ZFFTF AND ZFFTB
--C 18.  ZFFTF     FORWARD TRANSFORM OF A COMPLEX PERIODIC SEQUENCE
--C 19.  ZFFTB     UNNORMALIZED INVERSE OF ZFFTF
--C
--C
--C ******************************************************************
--C
--C SUBROUTINE DFFTI(N,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DFFTI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
--C BOTH DFFTF AND DFFTB. THE PRIME FACTORIZATION OF N TOGETHER WITH
--C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
--C STORED IN WSAVE.
--C
--C INPUT PARAMETER
--C
--C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED.
--C
--C OUTPUT PARAMETER
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 2*N+15.
--C         THE SAME WORK ARRAY CAN BE USED FOR BOTH DFFTF AND DFFTB
--C         AS LONG AS N REMAINS UNCHANGED. DIFFERENT WSAVE ARRAYS
--C         ARE REQUIRED FOR DIFFERENT VALUES OF N. THE CONTENTS OF
--C         WSAVE MUST NOT BE CHANGED BETWEEN CALLS OF DFFTF OR DFFTB.
--C
--C ******************************************************************
--C
--C SUBROUTINE DFFTF(N,R,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DFFTF COMPUTES THE FOURIER COEFFICIENTS OF A REAL
--C PERODIC SEQUENCE (FOURIER ANALYSIS). THE TRANSFORM IS DEFINED
--C BELOW AT OUTPUT PARAMETER R.
--C
--C INPUT PARAMETERS
--C
--C N       THE LENGTH OF THE ARRAY R TO BE TRANSFORMED.  THE METHOD
--C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
--C         N MAY CHANGE SO LONG AS DIFFERENT WORK ARRAYS ARE PROVIDED
--C
--C R       A REAL ARRAY OF LENGTH N WHICH CONTAINS THE SEQUENCE
--C         TO BE TRANSFORMED
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 2*N+15.
--C         IN THE PROGRAM THAT CALLS DFFTF. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE DFFTI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C         THE SAME WSAVE ARRAY CAN BE USED BY DFFTF AND DFFTB.
--C
--C
--C OUTPUT PARAMETERS
--C
--C R       R(1) = THE SUM FROM I=1 TO I=N OF R(I)
--C
--C         IF N IS EVEN SET L =N/2   , IF N IS ODD SET L = (N+1)/2
--C
--C           THEN FOR K = 2,...,L
--C
--C              R(2*K-2) = THE SUM FROM I = 1 TO I = N OF
--C
--C                   R(I)*COS((K-1)*(I-1)*2*PI/N)
--C
--C              R(2*K-1) = THE SUM FROM I = 1 TO I = N OF
--C
--C                  -R(I)*SIN((K-1)*(I-1)*2*PI/N)
--C
--C         IF N IS EVEN
--C
--C              R(N) = THE SUM FROM I = 1 TO I = N OF
--C
--C                   (-1)**(I-1)*R(I)
--C
--C  *****  NOTE
--C              THIS TRANSFORM IS UNNORMALIZED SINCE A CALL OF DFFTF
--C              FOLLOWED BY A CALL OF DFFTB WILL MULTIPLY THE INPUT
--C              SEQUENCE BY N.
--C
--C WSAVE   CONTAINS RESULTS WHICH MUST NOT BE DESTROYED BETWEEN
--C         CALLS OF DFFTF OR DFFTB.
--C
--C
--C ******************************************************************
--C
--C SUBROUTINE DFFTB(N,R,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DFFTB COMPUTES THE REAL PERODIC SEQUENCE FROM ITS
--C FOURIER COEFFICIENTS (FOURIER SYNTHESIS). THE TRANSFORM IS DEFINED
--C BELOW AT OUTPUT PARAMETER R.
--C
--C INPUT PARAMETERS
--C
--C N       THE LENGTH OF THE ARRAY R TO BE TRANSFORMED.  THE METHOD
--C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
--C         N MAY CHANGE SO LONG AS DIFFERENT WORK ARRAYS ARE PROVIDED
--C
--C R       A REAL ARRAY OF LENGTH N WHICH CONTAINS THE SEQUENCE
--C         TO BE TRANSFORMED
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 2*N+15.
--C         IN THE PROGRAM THAT CALLS DFFTB. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE DFFTI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C         THE SAME WSAVE ARRAY CAN BE USED BY DFFTF AND DFFTB.
--C
--C
--C OUTPUT PARAMETERS
--C
--C R       FOR N EVEN AND FOR I = 1,...,N
--C
--C              R(I) = R(1)+(-1)**(I-1)*R(N)
--C
--C                   PLUS THE SUM FROM K=2 TO K=N/2 OF
--C
--C                    2.*R(2*K-2)*COS((K-1)*(I-1)*2*PI/N)
--C
--C                   -2.*R(2*K-1)*SIN((K-1)*(I-1)*2*PI/N)
--C
--C         FOR N ODD AND FOR I = 1,...,N
--C
--C              R(I) = R(1) PLUS THE SUM FROM K=2 TO K=(N+1)/2 OF
--C
--C                   2.*R(2*K-2)*COS((K-1)*(I-1)*2*PI/N)
--C
--C                  -2.*R(2*K-1)*SIN((K-1)*(I-1)*2*PI/N)
--C
--C  *****  NOTE
--C              THIS TRANSFORM IS UNNORMALIZED SINCE A CALL OF DFFTF
--C              FOLLOWED BY A CALL OF DFFTB WILL MULTIPLY THE INPUT
--C              SEQUENCE BY N.
--C
--C WSAVE   CONTAINS RESULTS WHICH MUST NOT BE DESTROYED BETWEEN
--C         CALLS OF DFFTB OR DFFTF.
--C
--C
--C ******************************************************************
--C
--C SUBROUTINE DZFFTI(N,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DZFFTI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
--C BOTH DZFFTF AND DZFFTB. THE PRIME FACTORIZATION OF N TOGETHER WITH
--C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
--C STORED IN WSAVE.
--C
--C INPUT PARAMETER
--C
--C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED.
--C
--C OUTPUT PARAMETER
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
--C         THE SAME WORK ARRAY CAN BE USED FOR BOTH DZFFTF AND DZFFTB
--C         AS LONG AS N REMAINS UNCHANGED. DIFFERENT WSAVE ARRAYS
--C         ARE REQUIRED FOR DIFFERENT VALUES OF N.
--C
--C
--C ******************************************************************
--C
--C SUBROUTINE DZFFTF(N,R,AZERO,A,B,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DZFFTF COMPUTES THE FOURIER COEFFICIENTS OF A REAL
--C PERODIC SEQUENCE (FOURIER ANALYSIS). THE TRANSFORM IS DEFINED
--C BELOW AT OUTPUT PARAMETERS AZERO,A AND B. DZFFTF IS A SIMPLIFIED
--C BUT SLOWER VERSION OF DFFTF.
--C
--C INPUT PARAMETERS
--C
--C N       THE LENGTH OF THE ARRAY R TO BE TRANSFORMED.  THE METHOD
--C         IS MUST EFFICIENT WHEN N IS THE PRODUCT OF SMALL PRIMES.
--C
--C R       A REAL ARRAY OF LENGTH N WHICH CONTAINS THE SEQUENCE
--C         TO BE TRANSFORMED. R IS NOT DESTROYED.
--C
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
--C         IN THE PROGRAM THAT CALLS DZFFTF. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE DZFFTI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C         THE SAME WSAVE ARRAY CAN BE USED BY DZFFTF AND DZFFTB.
--C
--C OUTPUT PARAMETERS
--C
--C AZERO   THE SUM FROM I=1 TO I=N OF R(I)/N
--C
--C A,B     FOR N EVEN B(N/2)=0. AND A(N/2) IS THE SUM FROM I=1 TO
--C         I=N OF (-1)**(I-1)*R(I)/N
--C
--C         FOR N EVEN DEFINE KMAX=N/2-1
--C         FOR N ODD  DEFINE KMAX=(N-1)/2
--C
--C         THEN FOR  K=1,...,KMAX
--C
--C              A(K) EQUALS THE SUM FROM I=1 TO I=N OF
--C
--C                   2./N*R(I)*COS(K*(I-1)*2*PI/N)
--C
--C              B(K) EQUALS THE SUM FROM I=1 TO I=N OF
--C
--C                   2./N*R(I)*SIN(K*(I-1)*2*PI/N)
--C
--C
--C ******************************************************************
--C
--C SUBROUTINE DZFFTB(N,R,AZERO,A,B,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DZFFTB COMPUTES A REAL PERODIC SEQUENCE FROM ITS
--C FOURIER COEFFICIENTS (FOURIER SYNTHESIS). THE TRANSFORM IS
--C DEFINED BELOW AT OUTPUT PARAMETER R. DZFFTB IS A SIMPLIFIED
--C BUT SLOWER VERSION OF DFFTB.
--C
--C INPUT PARAMETERS
--C
--C N       THE LENGTH OF THE OUTPUT ARRAY R.  THE METHOD IS MOST
--C         EFFICIENT WHEN N IS THE PRODUCT OF SMALL PRIMES.
--C
--C AZERO   THE CONSTANT FOURIER COEFFICIENT
--C
--C A,B     ARRAYS WHICH CONTAIN THE REMAINING FOURIER COEFFICIENTS
--C         THESE ARRAYS ARE NOT DESTROYED.
--C
--C         THE LENGTH OF THESE ARRAYS DEPENDS ON WHETHER N IS EVEN OR
--C         ODD.
--C
--C         IF N IS EVEN N/2    LOCATIONS ARE REQUIRED
--C         IF N IS ODD (N-1)/2 LOCATIONS ARE REQUIRED
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
--C         IN THE PROGRAM THAT CALLS DZFFTB. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE DZFFTI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C         THE SAME WSAVE ARRAY CAN BE USED BY DZFFTF AND DZFFTB.
--C
--C
--C OUTPUT PARAMETERS
--C
--C R       IF N IS EVEN DEFINE KMAX=N/2
--C         IF N IS ODD  DEFINE KMAX=(N-1)/2
--C
--C         THEN FOR I=1,...,N
--C
--C              R(I)=AZERO PLUS THE SUM FROM K=1 TO K=KMAX OF
--C
--C              A(K)*COS(K*(I-1)*2*PI/N)+B(K)*SIN(K*(I-1)*2*PI/N)
--C
--C ********************* COMPLEX NOTATION **************************
--C
--C         FOR J=1,...,N
--C
--C         R(J) EQUALS THE SUM FROM K=-KMAX TO K=KMAX OF
--C
--C              C(K)*EXP(I*K*(J-1)*2*PI/N)
--C
--C         WHERE
--C
--C              C(K) = .5*CMPLX(A(K),-B(K))   FOR K=1,...,KMAX
--C
--C              C(-K) = CONJG(C(K))
--C
--C              C(0) = AZERO
--C
--C                   AND I=SQRT(-1)
--C
--C *************** AMPLITUDE - PHASE NOTATION ***********************
--C
--C         FOR I=1,...,N
--C
--C         R(I) EQUALS AZERO PLUS THE SUM FROM K=1 TO K=KMAX OF
--C
--C              ALPHA(K)*COS(K*(I-1)*2*PI/N+BETA(K))
--C
--C         WHERE
--C
--C              ALPHA(K) = SQRT(A(K)*A(K)+B(K)*B(K))
--C
--C              COS(BETA(K))=A(K)/ALPHA(K)
--C
--C              SIN(BETA(K))=-B(K)/ALPHA(K)
--C
--C ******************************************************************
--C
--C SUBROUTINE DSINTI(N,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DSINTI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
--C SUBROUTINE DSINT. THE PRIME FACTORIZATION OF N TOGETHER WITH
--C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
--C STORED IN WSAVE.
--C
--C INPUT PARAMETER
--C
--C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED.  THE METHOD
--C         IS MOST EFFICIENT WHEN N+1 IS A PRODUCT OF SMALL PRIMES.
--C
--C OUTPUT PARAMETER
--C
--C WSAVE   A WORK ARRAY WITH AT LEAST INT(2.5*N+15) LOCATIONS.
--C         DIFFERENT WSAVE ARRAYS ARE REQUIRED FOR DIFFERENT VALUES
--C         OF N. THE CONTENTS OF WSAVE MUST NOT BE CHANGED BETWEEN
--C         CALLS OF DSINT.
--C
--C ******************************************************************
--C
--C SUBROUTINE DSINT(N,X,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DSINT COMPUTES THE DISCRETE FOURIER SINE TRANSFORM
--C OF AN ODD SEQUENCE X(I). THE TRANSFORM IS DEFINED BELOW AT
--C OUTPUT PARAMETER X.
--C
--C DSINT IS THE UNNORMALIZED INVERSE OF ITSELF SINCE A CALL OF DSINT
--C FOLLOWED BY ANOTHER CALL OF DSINT WILL MULTIPLY THE INPUT SEQUENCE
--C X BY 2*(N+1).
--C
--C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DSINT MUST BE
--C INITIALIZED BY CALLING SUBROUTINE DSINTI(N,WSAVE).
--C
--C INPUT PARAMETERS
--C
--C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED.  THE METHOD
--C         IS MOST EFFICIENT WHEN N+1 IS THE PRODUCT OF SMALL PRIMES.
--C
--C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
--C
--C
--C WSAVE   A WORK ARRAY WITH DIMENSION AT LEAST INT(2.5*N+15)
--C         IN THE PROGRAM THAT CALLS DSINT. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE DSINTI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C
--C OUTPUT PARAMETERS
--C
--C X       FOR I=1,...,N
--C
--C              X(I)= THE SUM FROM K=1 TO K=N
--C
--C                   2*X(K)*SIN(K*I*PI/(N+1))
--C
--C              A CALL OF DSINT FOLLOWED BY ANOTHER CALL OF
--C              DSINT WILL MULTIPLY THE SEQUENCE X BY 2*(N+1).
--C              HENCE DSINT IS THE UNNORMALIZED INVERSE
--C              OF ITSELF.
--C
--C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT BE
--C         DESTROYED BETWEEN CALLS OF DSINT.
--C
--C ******************************************************************
--C
--C SUBROUTINE DCOSTI(N,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DCOSTI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
--C SUBROUTINE DCOST. THE PRIME FACTORIZATION OF N TOGETHER WITH
--C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
--C STORED IN WSAVE.
--C
--C INPUT PARAMETER
--C
--C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED.  THE METHOD
--C         IS MOST EFFICIENT WHEN N-1 IS A PRODUCT OF SMALL PRIMES.
--C
--C OUTPUT PARAMETER
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
--C         DIFFERENT WSAVE ARRAYS ARE REQUIRED FOR DIFFERENT VALUES
--C         OF N. THE CONTENTS OF WSAVE MUST NOT BE CHANGED BETWEEN
--C         CALLS OF DCOST.
--C
--C ******************************************************************
--C
--C SUBROUTINE DCOST(N,X,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DCOST COMPUTES THE DISCRETE FOURIER COSINE TRANSFORM
--C OF AN EVEN SEQUENCE X(I). THE TRANSFORM IS DEFINED BELOW AT OUTPUT
--C PARAMETER X.
--C
--C DCOST IS THE UNNORMALIZED INVERSE OF ITSELF SINCE A CALL OF DCOST
--C FOLLOWED BY ANOTHER CALL OF DCOST WILL MULTIPLY THE INPUT SEQUENCE
--C X BY 2*(N-1). THE TRANSFORM IS DEFINED BELOW AT OUTPUT PARAMETER X
--C
--C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DCOST MUST BE
--C INITIALIZED BY CALLING SUBROUTINE DCOSTI(N,WSAVE).
--C
--C INPUT PARAMETERS
--C
--C N       THE LENGTH OF THE SEQUENCE X. N MUST BE GREATER THAN 1.
--C         THE METHOD IS MOST EFFICIENT WHEN N-1 IS A PRODUCT OF
--C         SMALL PRIMES.
--C
--C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15
--C         IN THE PROGRAM THAT CALLS DCOST. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE DCOSTI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C
--C OUTPUT PARAMETERS
--C
--C X       FOR I=1,...,N
--C
--C             X(I) = X(1)+(-1)**(I-1)*X(N)
--C
--C              + THE SUM FROM K=2 TO K=N-1
--C
--C                  2*X(K)*COS((K-1)*(I-1)*PI/(N-1))
--C
--C              A CALL OF DCOST FOLLOWED BY ANOTHER CALL OF
--C              DCOST WILL MULTIPLY THE SEQUENCE X BY 2*(N-1)
--C              HENCE DCOST IS THE UNNORMALIZED INVERSE
--C              OF ITSELF.
--C
--C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT BE
--C         DESTROYED BETWEEN CALLS OF DCOST.
--C
--C ******************************************************************
--C
--C SUBROUTINE DSINQI(N,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DSINQI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
--C BOTH DSINQF AND DSINQB. THE PRIME FACTORIZATION OF N TOGETHER WITH
--C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
--C STORED IN WSAVE.
--C
--C INPUT PARAMETER
--C
--C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED. THE METHOD
--C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
--C
--C OUTPUT PARAMETER
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
--C         THE SAME WORK ARRAY CAN BE USED FOR BOTH DSINQF AND DSINQB
--C         AS LONG AS N REMAINS UNCHANGED. DIFFERENT WSAVE ARRAYS
--C         ARE REQUIRED FOR DIFFERENT VALUES OF N. THE CONTENTS OF
--C         WSAVE MUST NOT BE CHANGED BETWEEN CALLS OF DSINQF OR DSINQB.
--C
--C ******************************************************************
--C
--C SUBROUTINE DSINQF(N,X,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DSINQF COMPUTES THE FAST FOURIER TRANSFORM OF QUARTER
--C WAVE DATA. THAT IS , DSINQF COMPUTES THE COEFFICIENTS IN A SINE
--C SERIES REPRESENTATION WITH ONLY ODD WAVE NUMBERS. THE TRANSFORM
--C IS DEFINED BELOW AT OUTPUT PARAMETER X.
--C
--C DSINQB IS THE UNNORMALIZED INVERSE OF DSINQF SINCE A CALL OF DSINQF
--C FOLLOWED BY A CALL OF DSINQB WILL MULTIPLY THE INPUT SEQUENCE X
--C BY 4*N.
--C
--C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DSINQF MUST BE
--C INITIALIZED BY CALLING SUBROUTINE DSINQI(N,WSAVE).
--C
--C
--C INPUT PARAMETERS
--C
--C N       THE LENGTH OF THE ARRAY X TO BE TRANSFORMED.  THE METHOD
--C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
--C
--C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
--C         IN THE PROGRAM THAT CALLS DSINQF. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE DSINQI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C
--C OUTPUT PARAMETERS
--C
--C X       FOR I=1,...,N
--C
--C              X(I) = (-1)**(I-1)*X(N)
--C
--C                 + THE SUM FROM K=1 TO K=N-1 OF
--C
--C                 2*X(K)*SIN((2*I-1)*K*PI/(2*N))
--C
--C              A CALL OF DSINQF FOLLOWED BY A CALL OF
--C              DSINQB WILL MULTIPLY THE SEQUENCE X BY 4*N.
--C              THEREFORE DSINQB IS THE UNNORMALIZED INVERSE
--C              OF DSINQF.
--C
--C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT
--C         BE DESTROYED BETWEEN CALLS OF DSINQF OR DSINQB.
--C
--C ******************************************************************
--C
--C SUBROUTINE DSINQB(N,X,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DSINQB COMPUTES THE FAST FOURIER TRANSFORM OF QUARTER
--C WAVE DATA. THAT IS , DSINQB COMPUTES A SEQUENCE FROM ITS
--C REPRESENTATION IN TERMS OF A SINE SERIES WITH ODD WAVE NUMBERS.
--C THE TRANSFORM IS DEFINED BELOW AT OUTPUT PARAMETER X.
--C
--C DSINQF IS THE UNNORMALIZED INVERSE OF DSINQB SINCE A CALL OF DSINQB
--C FOLLOWED BY A CALL OF DSINQF WILL MULTIPLY THE INPUT SEQUENCE X
--C BY 4*N.
--C
--C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DSINQB MUST BE
--C INITIALIZED BY CALLING SUBROUTINE DSINQI(N,WSAVE).
--C
--C
--C INPUT PARAMETERS
--C
--C N       THE LENGTH OF THE ARRAY X TO BE TRANSFORMED.  THE METHOD
--C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
--C
--C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
--C         IN THE PROGRAM THAT CALLS DSINQB. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE DSINQI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C
--C OUTPUT PARAMETERS
--C
--C X       FOR I=1,...,N
--C
--C              X(I)= THE SUM FROM K=1 TO K=N OF
--C
--C                4*X(K)*SIN((2K-1)*I*PI/(2*N))
--C
--C              A CALL OF DSINQB FOLLOWED BY A CALL OF
--C              DSINQF WILL MULTIPLY THE SEQUENCE X BY 4*N.
--C              THEREFORE DSINQF IS THE UNNORMALIZED INVERSE
--C              OF DSINQB.
--C
--C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT
--C         BE DESTROYED BETWEEN CALLS OF DSINQB OR DSINQF.
--C
--C ******************************************************************
--C
--C SUBROUTINE DCOSQI(N,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DCOSQI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
--C BOTH DCOSQF AND DCOSQB. THE PRIME FACTORIZATION OF N TOGETHER WITH
--C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
--C STORED IN WSAVE.
--C
--C INPUT PARAMETER
--C
--C N       THE LENGTH OF THE ARRAY TO BE TRANSFORMED.  THE METHOD
--C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
--C
--C OUTPUT PARAMETER
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15.
--C         THE SAME WORK ARRAY CAN BE USED FOR BOTH DCOSQF AND DCOSQB
--C         AS LONG AS N REMAINS UNCHANGED. DIFFERENT WSAVE ARRAYS
--C         ARE REQUIRED FOR DIFFERENT VALUES OF N. THE CONTENTS OF
--C         WSAVE MUST NOT BE CHANGED BETWEEN CALLS OF DCOSQF OR DCOSQB.
--C
--C ******************************************************************
--C
--C SUBROUTINE DCOSQF(N,X,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DCOSQF COMPUTES THE FAST FOURIER TRANSFORM OF QUARTER
--C WAVE DATA. THAT IS , DCOSQF COMPUTES THE COEFFICIENTS IN A COSINE
--C SERIES REPRESENTATION WITH ONLY ODD WAVE NUMBERS. THE TRANSFORM
--C IS DEFINED BELOW AT OUTPUT PARAMETER X
--C
--C DCOSQF IS THE UNNORMALIZED INVERSE OF DCOSQB SINCE A CALL OF DCOSQF
--C FOLLOWED BY A CALL OF DCOSQB WILL MULTIPLY THE INPUT SEQUENCE X
--C BY 4*N.
--C
--C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DCOSQF MUST BE
--C INITIALIZED BY CALLING SUBROUTINE DCOSQI(N,WSAVE).
--C
--C
--C INPUT PARAMETERS
--C
--C N       THE LENGTH OF THE ARRAY X TO BE TRANSFORMED.  THE METHOD
--C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
--C
--C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 3*N+15
--C         IN THE PROGRAM THAT CALLS DCOSQF. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE DCOSQI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C
--C OUTPUT PARAMETERS
--C
--C X       FOR I=1,...,N
--C
--C              X(I) = X(1) PLUS THE SUM FROM K=2 TO K=N OF
--C
--C                 2*X(K)*COS((2*I-1)*(K-1)*PI/(2*N))
--C
--C              A CALL OF DCOSQF FOLLOWED BY A CALL OF
--C              DCOSQB WILL MULTIPLY THE SEQUENCE X BY 4*N.
--C              THEREFORE DCOSQB IS THE UNNORMALIZED INVERSE
--C              OF DCOSQF.
--C
--C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT
--C         BE DESTROYED BETWEEN CALLS OF DCOSQF OR DCOSQB.
--C
--C ******************************************************************
--C
--C SUBROUTINE DCOSQB(N,X,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE DCOSQB COMPUTES THE FAST FOURIER TRANSFORM OF QUARTER
--C WAVE DATA. THAT IS , DCOSQB COMPUTES A SEQUENCE FROM ITS
--C REPRESENTATION IN TERMS OF A COSINE SERIES WITH ODD WAVE NUMBERS.
--C THE TRANSFORM IS DEFINED BELOW AT OUTPUT PARAMETER X.
--C
--C DCOSQB IS THE UNNORMALIZED INVERSE OF DCOSQF SINCE A CALL OF DCOSQB
--C FOLLOWED BY A CALL OF DCOSQF WILL MULTIPLY THE INPUT SEQUENCE X
--C BY 4*N.
--C
--C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE DCOSQB MUST BE
--C INITIALIZED BY CALLING SUBROUTINE DCOSQI(N,WSAVE).
--C
--C
--C INPUT PARAMETERS
--C
--C N       THE LENGTH OF THE ARRAY X TO BE TRANSFORMED.  THE METHOD
--C         IS MOST EFFICIENT WHEN N IS A PRODUCT OF SMALL PRIMES.
--C
--C X       AN ARRAY WHICH CONTAINS THE SEQUENCE TO BE TRANSFORMED
--C
--C WSAVE   A WORK ARRAY THAT MUST BE DIMENSIONED AT LEAST 3*N+15
--C         IN THE PROGRAM THAT CALLS DCOSQB. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE DCOSQI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C
--C OUTPUT PARAMETERS
--C
--C X       FOR I=1,...,N
--C
--C              X(I)= THE SUM FROM K=1 TO K=N OF
--C
--C                4*X(K)*COS((2*K-1)*(I-1)*PI/(2*N))
--C
--C              A CALL OF DCOSQB FOLLOWED BY A CALL OF
--C              DCOSQF WILL MULTIPLY THE SEQUENCE X BY 4*N.
--C              THEREFORE DCOSQF IS THE UNNORMALIZED INVERSE
--C              OF DCOSQB.
--C
--C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT
--C         BE DESTROYED BETWEEN CALLS OF DCOSQB OR DCOSQF.
--C
--C ******************************************************************
--C
--C SUBROUTINE ZFFTI(N,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE ZFFTI INITIALIZES THE ARRAY WSAVE WHICH IS USED IN
--C BOTH ZFFTF AND ZFFTB. THE PRIME FACTORIZATION OF N TOGETHER WITH
--C A TABULATION OF THE TRIGONOMETRIC FUNCTIONS ARE COMPUTED AND
--C STORED IN WSAVE.
--C
--C INPUT PARAMETER
--C
--C N       THE LENGTH OF THE SEQUENCE TO BE TRANSFORMED
--C
--C OUTPUT PARAMETER
--C
--C WSAVE   A WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 4*N+15
--C         THE SAME WORK ARRAY CAN BE USED FOR BOTH ZFFTF AND ZFFTB
--C         AS LONG AS N REMAINS UNCHANGED. DIFFERENT WSAVE ARRAYS
--C         ARE REQUIRED FOR DIFFERENT VALUES OF N. THE CONTENTS OF
--C         WSAVE MUST NOT BE CHANGED BETWEEN CALLS OF ZFFTF OR ZFFTB.
--C
--C ******************************************************************
--C
--C SUBROUTINE ZFFTF(N,C,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE ZFFTF COMPUTES THE FORWARD COMPLEX DISCRETE FOURIER
--C TRANSFORM (THE FOURIER ANALYSIS). EQUIVALENTLY , ZFFTF COMPUTES
--C THE FOURIER COEFFICIENTS OF A COMPLEX PERIODIC SEQUENCE.
--C THE TRANSFORM IS DEFINED BELOW AT OUTPUT PARAMETER C.
--C
--C THE TRANSFORM IS NOT NORMALIZED. TO OBTAIN A NORMALIZED TRANSFORM
--C THE OUTPUT MUST BE DIVIDED BY N. OTHERWISE A CALL OF ZFFTF
--C FOLLOWED BY A CALL OF ZFFTB WILL MULTIPLY THE SEQUENCE BY N.
--C
--C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE ZFFTF MUST BE
--C INITIALIZED BY CALLING SUBROUTINE ZFFTI(N,WSAVE).
--C
--C INPUT PARAMETERS
--C
--C
--C N      THE LENGTH OF THE COMPLEX SEQUENCE C. THE METHOD IS
--C        MORE EFFICIENT WHEN N IS THE PRODUCT OF SMALL PRIMES. N
--C
--C C      A COMPLEX ARRAY OF LENGTH N WHICH CONTAINS THE SEQUENCE
--C
--C WSAVE   A REAL WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 4N+15
--C         IN THE PROGRAM THAT CALLS ZFFTF. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE ZFFTI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C         THE SAME WSAVE ARRAY CAN BE USED BY ZFFTF AND ZFFTB.
--C
--C OUTPUT PARAMETERS
--C
--C C      FOR J=1,...,N
--C
--C            C(J)=THE SUM FROM K=1,...,N OF
--C
--C                  C(K)*EXP(-I*(J-1)*(K-1)*2*PI/N)
--C
--C                        WHERE I=SQRT(-1)
--C
--C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT BE
--C         DESTROYED BETWEEN CALLS OF SUBROUTINE ZFFTF OR ZFFTB
--C
--C ******************************************************************
--C
--C SUBROUTINE ZFFTB(N,C,WSAVE)
--C
--C ******************************************************************
--C
--C SUBROUTINE ZFFTB COMPUTES THE BACKWARD COMPLEX DISCRETE FOURIER
--C TRANSFORM (THE FOURIER SYNTHESIS). EQUIVALENTLY , ZFFTB COMPUTES
--C A COMPLEX PERIODIC SEQUENCE FROM ITS FOURIER COEFFICIENTS.
--C THE TRANSFORM IS DEFINED BELOW AT OUTPUT PARAMETER C.
--C
--C A CALL OF ZFFTF FOLLOWED BY A CALL OF ZFFTB WILL MULTIPLY THE
--C SEQUENCE BY N.
--C
--C THE ARRAY WSAVE WHICH IS USED BY SUBROUTINE ZFFTB MUST BE
--C INITIALIZED BY CALLING SUBROUTINE ZFFTI(N,WSAVE).
--C
--C INPUT PARAMETERS
--C
--C
--C N      THE LENGTH OF THE COMPLEX SEQUENCE C. THE METHOD IS
--C        MORE EFFICIENT WHEN N IS THE PRODUCT OF SMALL PRIMES.
--C
--C C      A COMPLEX ARRAY OF LENGTH N WHICH CONTAINS THE SEQUENCE
--C
--C WSAVE   A REAL WORK ARRAY WHICH MUST BE DIMENSIONED AT LEAST 4N+15
--C         IN THE PROGRAM THAT CALLS ZFFTB. THE WSAVE ARRAY MUST BE
--C         INITIALIZED BY CALLING SUBROUTINE ZFFTI(N,WSAVE) AND A
--C         DIFFERENT WSAVE ARRAY MUST BE USED FOR EACH DIFFERENT
--C         VALUE OF N. THIS INITIALIZATION DOES NOT HAVE TO BE
--C         REPEATED SO LONG AS N REMAINS UNCHANGED THUS SUBSEQUENT
--C         TRANSFORMS CAN BE OBTAINED FASTER THAN THE FIRST.
--C         THE SAME WSAVE ARRAY CAN BE USED BY ZFFTF AND ZFFTB.
--C
--C OUTPUT PARAMETERS
--C
--C C      FOR J=1,...,N
--C
--C            C(J)=THE SUM FROM K=1,...,N OF
--C
--C                  C(K)*EXP(I*(J-1)*(K-1)*2*PI/N)
--C
--C                        WHERE I=SQRT(-1)
--C
--C WSAVE   CONTAINS INITIALIZATION CALCULATIONS WHICH MUST NOT BE
--C         DESTROYED BETWEEN CALLS OF SUBROUTINE ZFFTF OR ZFFTB
--C
--C
--C
--C ["SEND INDEX FOR VFFTPK" DESCRIBES A VECTORIZED VERSION OF FFTPACK]
--C
--C
--C
--
--      SUBROUTINE ZFFTB1 (N,C,CH,WA,IFAC)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CH(*)      ,C(*)       ,WA(*)      ,IFAC(*)
--      NF = IFAC(2)
--      NA = 0
--      L1 = 1
--      IW = 1
--      DO 116 K1=1,NF
--         IP = IFAC(K1+2)
--         L2 = IP*L1
--         IDO = N/L2
--         IDOT = IDO+IDO
--         IDL1 = IDOT*L1
--         IF (IP .NE. 4) GO TO 103
--         IX2 = IW+IDOT
--         IX3 = IX2+IDOT
--         IF (NA .NE. 0) GO TO 101
--         CALL DPASSB4 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3))
--         GO TO 102
--  101    CALL DPASSB4 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3))
--  102    NA = 1-NA
--         GO TO 115
--  103    IF (IP .NE. 2) GO TO 106
--         IF (NA .NE. 0) GO TO 104
--         CALL DPASSB2 (IDOT,L1,C,CH,WA(IW))
--         GO TO 105
--  104    CALL DPASSB2 (IDOT,L1,CH,C,WA(IW))
--  105    NA = 1-NA
--         GO TO 115
--  106    IF (IP .NE. 3) GO TO 109
--         IX2 = IW+IDOT
--         IF (NA .NE. 0) GO TO 107
--         CALL DPASSB3 (IDOT,L1,C,CH,WA(IW),WA(IX2))
--         GO TO 108
--  107    CALL DPASSB3 (IDOT,L1,CH,C,WA(IW),WA(IX2))
--  108    NA = 1-NA
--         GO TO 115
--  109    IF (IP .NE. 5) GO TO 112
--         IX2 = IW+IDOT
--         IX3 = IX2+IDOT
--         IX4 = IX3+IDOT
--         IF (NA .NE. 0) GO TO 110
--         CALL DPASSB5 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4))
--         GO TO 111
--  110    CALL DPASSB5 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4))
--  111    NA = 1-NA
--         GO TO 115
--  112    IF (NA .NE. 0) GO TO 113
--         CALL DPASSB (NAC,IDOT,IP,L1,IDL1,C,C,C,CH,CH,WA(IW))
--         GO TO 114
--  113    CALL DPASSB (NAC,IDOT,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW))
--  114    IF (NAC .NE. 0) NA = 1-NA
--  115    L1 = L2
--         IW = IW+(IP-1)*IDOT
--  116 CONTINUE
--      IF (NA .EQ. 0) RETURN
--      N2 = N+N
--      DO 117 I=1,N2
--         C(I) = CH(I)
--  117 CONTINUE
--      RETURN
--      END
--
--      SUBROUTINE ZFFTB (N,C,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       C(*)       ,WSAVE(*)
--      IF (N .EQ. 1) RETURN
--      IW1 = N+N+1
--      IW2 = IW1+N+N
--      CALL ZFFTB1 (N,C,WSAVE,WSAVE(IW1),WSAVE(IW2))
--      RETURN
--      END
--
--      SUBROUTINE ZFFTF1 (N,C,CH,WA,IFAC)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CH(*)      ,C(*)       ,WA(*)      ,IFAC(*)
--      NF = IFAC(2)
--      NA = 0
--      L1 = 1
--      IW = 1
--      DO 116 K1=1,NF
--         IP = IFAC(K1+2)
--         L2 = IP*L1
--         IDO = N/L2
--         IDOT = IDO+IDO
--         IDL1 = IDOT*L1
--         IF (IP .NE. 4) GO TO 103
--         IX2 = IW+IDOT
--         IX3 = IX2+IDOT
--         IF (NA .NE. 0) GO TO 101
--         CALL DPASSF4 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3))
--         GO TO 102
--  101    CALL DPASSF4 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3))
--  102    NA = 1-NA
--         GO TO 115
--  103    IF (IP .NE. 2) GO TO 106
--         IF (NA .NE. 0) GO TO 104
--         CALL DPASSF2 (IDOT,L1,C,CH,WA(IW))
--         GO TO 105
--  104    CALL DPASSF2 (IDOT,L1,CH,C,WA(IW))
--  105    NA = 1-NA
--         GO TO 115
--  106    IF (IP .NE. 3) GO TO 109
--         IX2 = IW+IDOT
--         IF (NA .NE. 0) GO TO 107
--         CALL DPASSF3 (IDOT,L1,C,CH,WA(IW),WA(IX2))
--         GO TO 108
--  107    CALL DPASSF3 (IDOT,L1,CH,C,WA(IW),WA(IX2))
--  108    NA = 1-NA
--         GO TO 115
--  109    IF (IP .NE. 5) GO TO 112
--         IX2 = IW+IDOT
--         IX3 = IX2+IDOT
--         IX4 = IX3+IDOT
--         IF (NA .NE. 0) GO TO 110
--         CALL DPASSF5 (IDOT,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4))
--         GO TO 111
--  110    CALL DPASSF5 (IDOT,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4))
--  111    NA = 1-NA
--         GO TO 115
--  112    IF (NA .NE. 0) GO TO 113
--         CALL DPASSF (NAC,IDOT,IP,L1,IDL1,C,C,C,CH,CH,WA(IW))
--         GO TO 114
--  113    CALL DPASSF (NAC,IDOT,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW))
--  114    IF (NAC .NE. 0) NA = 1-NA
--  115    L1 = L2
--         IW = IW+(IP-1)*IDOT
--  116 CONTINUE
--      IF (NA .EQ. 0) RETURN
--      N2 = N+N
--      DO 117 I=1,N2
--         C(I) = CH(I)
--  117 CONTINUE
--      RETURN
--      END
--
--
--      SUBROUTINE ZFFTF (N,C,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       C(*)       ,WSAVE(*)
--      IF (N .EQ. 1) RETURN
--      IW1 = N+N+1
--      IW2 = IW1+N+N
--      CALL ZFFTF1 (N,C,WSAVE,WSAVE(IW1),WSAVE(IW2))
--      RETURN
--      END
--
--
--      SUBROUTINE ZFFTI1 (N,WA,IFAC)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       WA(*)      ,IFAC(*)    ,NTRYH(4)
--      DATA NTRYH(1),NTRYH(2),NTRYH(3),NTRYH(4)/3,4,2,5/
--      NL = N
--      NF = 0
--      J = 0
--  101 J = J+1
--      IF (J-4) 102,102,103
--  102 NTRY = NTRYH(J)
--      GO TO 104
--  103 NTRY = NTRY+2
--  104 NQ = NL/NTRY
--      NR = NL-NTRY*NQ
--      IF (NR) 101,105,101
--  105 NF = NF+1
--      IFAC(NF+2) = NTRY
--      NL = NQ
--      IF (NTRY .NE. 2) GO TO 107
--      IF (NF .EQ. 1) GO TO 107
--      DO 106 I=2,NF
--         IB = NF-I+2
--         IFAC(IB+2) = IFAC(IB+1)
--  106 CONTINUE
--      IFAC(3) = 2
--  107 IF (NL .NE. 1) GO TO 104
--      IFAC(1) = N
--      IFAC(2) = NF
--      TPI = 6.2831853071795864769252867665590057D0
--      ARGH = TPI/DBLE(N)
--      I = 2
--      L1 = 1
--      DO 110 K1=1,NF
--         IP = IFAC(K1+2)
--         LD = 0
--         L2 = L1*IP
--         IDO = N/L2
--         IDOT = IDO+IDO+2
--         IPM = IP-1
--         DO 109 J=1,IPM
--            I1 = I
--            WA(I-1) = 1.0D0
--            WA(I) = 0.0D0
--            LD = LD+L1
--            FI = 0.0D0
--            ARGLD = DBLE(LD)*ARGH
--            DO 108 II=4,IDOT,2
--               I = I+2
--               FI = FI+1.0D0
--               ARG = FI*ARGLD
--               WA(I-1) = DCOS(ARG)
--               WA(I) = DSIN(ARG)
--  108       CONTINUE
--            IF (IP .LE. 5) GO TO 109
--            WA(I1-1) = WA(I-1)
--            WA(I1) = WA(I)
--  109    CONTINUE
--         L1 = L2
--  110 CONTINUE
--      RETURN
--      END
--
--      SUBROUTINE ZFFTI (N,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       WSAVE(*)
--      IF (N .EQ. 1) RETURN
--      IW1 = N+N+1
--      IW2 = IW1+N+N
--      CALL ZFFTI1 (N,WSAVE(IW1),WSAVE(IW2))
--      RETURN
--      END
--
--      SUBROUTINE DCOSQB1 (N,X,W,XH)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       X(*)       ,W(*)       ,XH(*)
--      NS2 = (N+1)/2
--      NP2 = N+2
--      DO 101 I=3,N,2
--         XIM1 = X(I-1)+X(I)
--         X(I) = X(I)-X(I-1)
--         X(I-1) = XIM1
--  101 CONTINUE
--      X(1) = X(1)+X(1)
--      MODN = MOD(N,2)
--      IF (MODN .EQ. 0) X(N) = X(N)+X(N)
--      CALL DFFTB (N,X,XH)
--      DO 102 K=2,NS2
--         KC = NP2-K
--         XH(K) = W(K-1)*X(KC)+W(KC-1)*X(K)
--         XH(KC) = W(K-1)*X(K)-W(KC-1)*X(KC)
--  102 CONTINUE
--      IF (MODN .EQ. 0) X(NS2+1) = W(NS2)*(X(NS2+1)+X(NS2+1))
--      DO 103 K=2,NS2
--         KC = NP2-K
--         X(K) = XH(K)+XH(KC)
--         X(KC) = XH(K)-XH(KC)
--  103 CONTINUE
--      X(1) = X(1)+X(1)
--      RETURN
--      END
--
--      SUBROUTINE DCOSQF1 (N,X,W,XH)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       X(*)       ,W(*)       ,XH(*)
--      NS2 = (N+1)/2
--      NP2 = N+2
--      DO 101 K=2,NS2
--         KC = NP2-K
--         XH(K) = X(K)+X(KC)
--         XH(KC) = X(K)-X(KC)
--  101 CONTINUE
--      MODN = MOD(N,2)
--      IF (MODN .EQ. 0) XH(NS2+1) = X(NS2+1)+X(NS2+1)
--      DO 102 K=2,NS2
--         KC = NP2-K
--         X(K) = W(K-1)*XH(KC)+W(KC-1)*XH(K)
--         X(KC) = W(K-1)*XH(K)-W(KC-1)*XH(KC)
--  102 CONTINUE
--      IF (MODN .EQ. 0) X(NS2+1) = W(NS2)*XH(NS2+1)
--      CALL DFFTF (N,X,XH)
--      DO 103 I=3,N,2
--         XIM1 = X(I-1)-X(I)
--         X(I) = X(I-1)+X(I)
--         X(I-1) = XIM1
--  103 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DCOSQI (N,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       WSAVE(*)
--      DATA PIH /1.5707963267948966192313216916397514D0/
--      DT = PIH/DBLE(N)
--      FK = 0.0D0
--      DO 101 K=1,N
--         FK = FK+1.0D0
--         WSAVE(K) = DCOS(FK*DT)
--  101 CONTINUE
--      CALL DFFTI (N,WSAVE(N+1))
--      RETURN
--      END
--      SUBROUTINE DCOST (N,X,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       X(*)       ,WSAVE(*)
--      NM1 = N-1
--      NP1 = N+1
--      NS2 = N/2
--      IF (N-2) 106,101,102
--  101 X1H = X(1)+X(2)
--      X(2) = X(1)-X(2)
--      X(1) = X1H
--      RETURN
--  102 IF (N .GT. 3) GO TO 103
--      X1P3 = X(1)+X(3)
--      TX2 = X(2)+X(2)
--      X(2) = X(1)-X(3)
--      X(1) = X1P3+TX2
--      X(3) = X1P3-TX2
--      RETURN
--  103 C1 = X(1)-X(N)
--      X(1) = X(1)+X(N)
--      DO 104 K=2,NS2
--         KC = NP1-K
--         T1 = X(K)+X(KC)
--         T2 = X(K)-X(KC)
--         C1 = C1+WSAVE(KC)*T2
--         T2 = WSAVE(K)*T2
--         X(K) = T1-T2
--         X(KC) = T1+T2
--  104 CONTINUE
--      MODN = MOD(N,2)
--      IF (MODN .NE. 0) X(NS2+1) = X(NS2+1)+X(NS2+1)
--      CALL DFFTF (NM1,X,WSAVE(N+1))
--      XIM2 = X(2)
--      X(2) = C1
--      DO 105 I=4,N,2
--         XI = X(I)
--         X(I) = X(I-2)-X(I-1)
--         X(I-1) = XIM2
--         XIM2 = XI
--  105 CONTINUE
--      IF (MODN .NE. 0) X(N) = XIM2
--  106 RETURN
--      END
--
--      SUBROUTINE DZFFT1 (N,WA,IFAC)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       WA(*)      ,IFAC(*)    ,NTRYH(4)
--      DATA NTRYH(1),NTRYH(2),NTRYH(3),NTRYH(4)/4,2,3,5/
--     1    ,TPI/6.2831853071795864769252867665590057D0/
--      NL = N
--      NF = 0
--      J = 0
--  101 J = J+1
--      IF (J-4) 102,102,103
--  102 NTRY = NTRYH(J)
--      GO TO 104
--  103 NTRY = NTRY+2
--  104 NQ = NL/NTRY
--      NR = NL-NTRY*NQ
--      IF (NR) 101,105,101
--  105 NF = NF+1
--      IFAC(NF+2) = NTRY
--      NL = NQ
--      IF (NTRY .NE. 2) GO TO 107
--      IF (NF .EQ. 1) GO TO 107
--      DO 106 I=2,NF
--         IB = NF-I+2
--         IFAC(IB+2) = IFAC(IB+1)
--  106 CONTINUE
--      IFAC(3) = 2
--  107 IF (NL .NE. 1) GO TO 104
--      IFAC(1) = N
--      IFAC(2) = NF
--      ARGH = TPI/DBLE(N)
--      IS = 0
--      NFM1 = NF-1
--      L1 = 1
--      IF (NFM1 .EQ. 0) RETURN
--      DO 111 K1=1,NFM1
--         IP = IFAC(K1+2)
--         L2 = L1*IP
--         IDO = N/L2
--         IPM = IP-1
--         ARG1 = DBLE(L1)*ARGH
--         CH1 = 1.0D0
--         SH1 = 0.0D0
--         DCH1 = DCOS(ARG1)
--         DSH1 = DSIN(ARG1)
--         DO 110 J=1,IPM
--            CH1H = DCH1*CH1-DSH1*SH1
--            SH1 = DCH1*SH1+DSH1*CH1
--            CH1 = CH1H
--            I = IS+2
--            WA(I-1) = CH1
--            WA(I) = SH1
--            IF (IDO .LT. 5) GO TO 109
--            DO 108 II=5,IDO,2
--               I = I+2
--               WA(I-1) = CH1*WA(I-3)-SH1*WA(I-2)
--               WA(I) = CH1*WA(I-2)+SH1*WA(I-3)
--  108       CONTINUE
--  109       IS = IS+IDO
--  110    CONTINUE
--         L1 = L2
--  111 CONTINUE
--      RETURN
--      END
--
--      SUBROUTINE DCOSQB (N,X,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       X(*)       ,WSAVE(*)
--      DATA TSQRT2 /2.8284271247461900976033774484193961D0/
--      IF (N-2) 101,102,103
--  101 X(1) = 4.0D0*X(1)
--      RETURN
--  102 X1 = 4.0D0*(X(1)+X(2))
--      X(2) = TSQRT2*(X(1)-X(2))
--      X(1) = X1
--      RETURN
--  103 CALL DCOSQB1 (N,X,WSAVE,WSAVE(N+1))
--      RETURN
--      END
--      SUBROUTINE DCOSQF (N,X,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       X(*)       ,WSAVE(*)
--      DATA SQRT2 /1.4142135623730950488016887242096980D0/
--      IF (N-2) 102,101,103
--  101 TSQX = SQRT2*X(2)
--      X(2) = X(1)-TSQX
--      X(1) = X(1)+TSQX
--  102 RETURN
--  103 CALL DCOSQF1 (N,X,WSAVE,WSAVE(N+1))
--      RETURN
--      END
--      SUBROUTINE DCOSTI (N,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       WSAVE(*)
--      DATA PI /3.1415926535897932384626433832795028D0/
--      IF (N .LE. 3) RETURN
--      NM1 = N-1
--      NP1 = N+1
--      NS2 = N/2
--      DT = PI/DBLE(NM1)
--      FK = 0.0D0
--      DO 101 K=2,NS2
--         KC = NP1-K
--         FK = FK+1.0D0
--         WSAVE(K) = 2.0D0*DSIN(FK*DT)
--         WSAVE(KC) = 2.0D0*DCOS(FK*DT)
--  101 CONTINUE
--      CALL DFFTI (NM1,WSAVE(N+1))
--      RETURN
--      END
--
--      SUBROUTINE DZFFTB (N,R,AZERO,A,B,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       R(*)       ,A(*)       ,B(*)       ,WSAVE(*)
--      IF (N-2) 101,102,103
--  101 R(1) = AZERO
--      RETURN
--  102 R(1) = AZERO+A(1)
--      R(2) = AZERO-A(1)
--      RETURN
--  103 NS2 = (N-1)/2
--      DO 104 I=1,NS2
--         R(2*I) = .5D0*A(I)
--         R(2*I+1) = -.5D0*B(I)
--  104 CONTINUE
--      R(1) = AZERO
--      IF (MOD(N,2) .EQ. 0) R(N) = A(NS2+1)
--      CALL DFFTB (N,R,WSAVE(N+1))
--      RETURN
--      END
--      SUBROUTINE DZFFTF (N,R,AZERO,A,B,WSAVE)
--C
--C                       VERSION 3  JUNE 1979
--C
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       R(*)       ,A(*)       ,B(*)       ,WSAVE(*)
--      IF (N-2) 101,102,103
--  101 AZERO = R(1)
--      RETURN
--  102 AZERO = .5D0*(R(1)+R(2))
--      A(1) = .5D0*(R(1)-R(2))
--      RETURN
--  103 DO 104 I=1,N
--         WSAVE(I) = R(I)
--  104 CONTINUE
--      CALL DFFTF (N,WSAVE,WSAVE(N+1))
--      CF = 2.0D0/DBLE(N)
--      CFM = -CF
--      AZERO = .5D0*CF*WSAVE(1)
--      NS2 = (N+1)/2
--      NS2M = NS2-1
--      DO 105 I=1,NS2M
--         A(I) = CF*WSAVE(2*I)
--         B(I) = CFM*WSAVE(2*I+1)
--  105 CONTINUE
--      IF (MOD(N,2) .EQ. 1) RETURN
--      A(NS2) = .5D0*CF*WSAVE(N)
--      B(NS2) = 0.0D0
--      RETURN
--      END
--      SUBROUTINE DZFFTI (N,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       WSAVE(*)
--      IF (N .EQ. 1) RETURN
--      CALL DZFFT1 (N,WSAVE(2*N+1),WSAVE(3*N+1))
--      RETURN
--      END
--      SUBROUTINE DPASSB (NAC,IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CH(IDO,L1,IP)          ,CC(IDO,IP,L1)          ,
--     1                C1(IDO,L1,IP)          ,WA(*)      ,C2(IDL1,IP),
--     2                CH2(IDL1,IP)
--      IDOT = IDO/2
--      NT = IP*IDL1
--      IPP2 = IP+2
--      IPPH = (IP+1)/2
--      IDP = IP*IDO
--C
--      IF (IDO .LT. L1) GO TO 106
--      DO 103 J=2,IPPH
--         JC = IPP2-J
--         DO 102 K=1,L1
--            DO 101 I=1,IDO
--               CH(I,K,J) = CC(I,J,K)+CC(I,JC,K)
--               CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K)
--  101       CONTINUE
--  102    CONTINUE
--  103 CONTINUE
--      DO 105 K=1,L1
--         DO 104 I=1,IDO
--            CH(I,K,1) = CC(I,1,K)
--  104    CONTINUE
--  105 CONTINUE
--      GO TO 112
--  106 DO 109 J=2,IPPH
--         JC = IPP2-J
--         DO 108 I=1,IDO
--            DO 107 K=1,L1
--               CH(I,K,J) = CC(I,J,K)+CC(I,JC,K)
--               CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K)
--  107       CONTINUE
--  108    CONTINUE
--  109 CONTINUE
--      DO 111 I=1,IDO
--         DO 110 K=1,L1
--            CH(I,K,1) = CC(I,1,K)
--  110    CONTINUE
--  111 CONTINUE
--  112 IDL = 2-IDO
--      INC = 0
--      DO 116 L=2,IPPH
--         LC = IPP2-L
--         IDL = IDL+IDO
--         DO 113 IK=1,IDL1
--            C2(IK,L) = CH2(IK,1)+WA(IDL-1)*CH2(IK,2)
--            C2(IK,LC) = WA(IDL)*CH2(IK,IP)
--  113    CONTINUE
--         IDLJ = IDL
--         INC = INC+IDO
--         DO 115 J=3,IPPH
--            JC = IPP2-J
--            IDLJ = IDLJ+INC
--            IF (IDLJ .GT. IDP) IDLJ = IDLJ-IDP
--            WAR = WA(IDLJ-1)
--            WAI = WA(IDLJ)
--            DO 114 IK=1,IDL1
--               C2(IK,L) = C2(IK,L)+WAR*CH2(IK,J)
--               C2(IK,LC) = C2(IK,LC)+WAI*CH2(IK,JC)
--  114       CONTINUE
--  115    CONTINUE
--  116 CONTINUE
--      DO 118 J=2,IPPH
--         DO 117 IK=1,IDL1
--            CH2(IK,1) = CH2(IK,1)+CH2(IK,J)
--  117    CONTINUE
--  118 CONTINUE
--      DO 120 J=2,IPPH
--         JC = IPP2-J
--         DO 119 IK=2,IDL1,2
--            CH2(IK-1,J) = C2(IK-1,J)-C2(IK,JC)
--            CH2(IK-1,JC) = C2(IK-1,J)+C2(IK,JC)
--            CH2(IK,J) = C2(IK,J)+C2(IK-1,JC)
--            CH2(IK,JC) = C2(IK,J)-C2(IK-1,JC)
--  119    CONTINUE
--  120 CONTINUE
--      NAC = 1
--      IF (IDO .EQ. 2) RETURN
--      NAC = 0
--      DO 121 IK=1,IDL1
--         C2(IK,1) = CH2(IK,1)
--  121 CONTINUE
--      DO 123 J=2,IP
--         DO 122 K=1,L1
--            C1(1,K,J) = CH(1,K,J)
--            C1(2,K,J) = CH(2,K,J)
--  122    CONTINUE
--  123 CONTINUE
--      IF (IDOT .GT. L1) GO TO 127
--      IDIJ = 0
--      DO 126 J=2,IP
--         IDIJ = IDIJ+2
--         DO 125 I=4,IDO,2
--            IDIJ = IDIJ+2
--            DO 124 K=1,L1
--               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J)
--               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J)
--  124       CONTINUE
--  125    CONTINUE
--  126 CONTINUE
--      RETURN
--  127 IDJ = 2-IDO
--      DO 130 J=2,IP
--         IDJ = IDJ+IDO
--         DO 129 K=1,L1
--            IDIJ = IDJ
--            DO 128 I=4,IDO,2
--               IDIJ = IDIJ+2
--               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J)
--               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J)
--  128       CONTINUE
--  129    CONTINUE
--  130 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DPASSB2 (IDO,L1,CC,CH,WA1)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,2,L1)           ,CH(IDO,L1,2)           ,
--     1                WA1(*)
--      IF (IDO .GT. 2) GO TO 102
--      DO 101 K=1,L1
--         CH(1,K,1) = CC(1,1,K)+CC(1,2,K)
--         CH(1,K,2) = CC(1,1,K)-CC(1,2,K)
--         CH(2,K,1) = CC(2,1,K)+CC(2,2,K)
--         CH(2,K,2) = CC(2,1,K)-CC(2,2,K)
--  101 CONTINUE
--      RETURN
--  102 DO 104 K=1,L1
--         DO 103 I=2,IDO,2
--            CH(I-1,K,1) = CC(I-1,1,K)+CC(I-1,2,K)
--            TR2 = CC(I-1,1,K)-CC(I-1,2,K)
--            CH(I,K,1) = CC(I,1,K)+CC(I,2,K)
--            TI2 = CC(I,1,K)-CC(I,2,K)
--            CH(I,K,2) = WA1(I-1)*TI2+WA1(I)*TR2
--            CH(I-1,K,2) = WA1(I-1)*TR2-WA1(I)*TI2
--  103    CONTINUE
--  104 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DPASSB3 (IDO,L1,CC,CH,WA1,WA2)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,3,L1)           ,CH(IDO,L1,3)           ,
--     1                WA1(*)     ,WA2(*)
--      DATA TAUR,TAUI /-.5D0,.86602540378443864676372317075293618D0/
--      IF (IDO .NE. 2) GO TO 102
--      DO 101 K=1,L1
--         TR2 = CC(1,2,K)+CC(1,3,K)
--         CR2 = CC(1,1,K)+TAUR*TR2
--         CH(1,K,1) = CC(1,1,K)+TR2
--         TI2 = CC(2,2,K)+CC(2,3,K)
--         CI2 = CC(2,1,K)+TAUR*TI2
--         CH(2,K,1) = CC(2,1,K)+TI2
--         CR3 = TAUI*(CC(1,2,K)-CC(1,3,K))
--         CI3 = TAUI*(CC(2,2,K)-CC(2,3,K))
--         CH(1,K,2) = CR2-CI3
--         CH(1,K,3) = CR2+CI3
--         CH(2,K,2) = CI2+CR3
--         CH(2,K,3) = CI2-CR3
--  101 CONTINUE
--      RETURN
--  102 DO 104 K=1,L1
--         DO 103 I=2,IDO,2
--            TR2 = CC(I-1,2,K)+CC(I-1,3,K)
--            CR2 = CC(I-1,1,K)+TAUR*TR2
--            CH(I-1,K,1) = CC(I-1,1,K)+TR2
--            TI2 = CC(I,2,K)+CC(I,3,K)
--            CI2 = CC(I,1,K)+TAUR*TI2
--            CH(I,K,1) = CC(I,1,K)+TI2
--            CR3 = TAUI*(CC(I-1,2,K)-CC(I-1,3,K))
--            CI3 = TAUI*(CC(I,2,K)-CC(I,3,K))
--            DR2 = CR2-CI3
--            DR3 = CR2+CI3
--            DI2 = CI2+CR3
--            DI3 = CI2-CR3
--            CH(I,K,2) = WA1(I-1)*DI2+WA1(I)*DR2
--            CH(I-1,K,2) = WA1(I-1)*DR2-WA1(I)*DI2
--            CH(I,K,3) = WA2(I-1)*DI3+WA2(I)*DR3
--            CH(I-1,K,3) = WA2(I-1)*DR3-WA2(I)*DI3
--  103    CONTINUE
--  104 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DPASSB4 (IDO,L1,CC,CH,WA1,WA2,WA3)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,4,L1)           ,CH(IDO,L1,4)           ,
--     1                WA1(*)     ,WA2(*)     ,WA3(*)
--      IF (IDO .NE. 2) GO TO 102
--      DO 101 K=1,L1
--         TI1 = CC(2,1,K)-CC(2,3,K)
--         TI2 = CC(2,1,K)+CC(2,3,K)
--         TR4 = CC(2,4,K)-CC(2,2,K)
--         TI3 = CC(2,2,K)+CC(2,4,K)
--         TR1 = CC(1,1,K)-CC(1,3,K)
--         TR2 = CC(1,1,K)+CC(1,3,K)
--         TI4 = CC(1,2,K)-CC(1,4,K)
--         TR3 = CC(1,2,K)+CC(1,4,K)
--         CH(1,K,1) = TR2+TR3
--         CH(1,K,3) = TR2-TR3
--         CH(2,K,1) = TI2+TI3
--         CH(2,K,3) = TI2-TI3
--         CH(1,K,2) = TR1+TR4
--         CH(1,K,4) = TR1-TR4
--         CH(2,K,2) = TI1+TI4
--         CH(2,K,4) = TI1-TI4
--  101 CONTINUE
--      RETURN
--  102 DO 104 K=1,L1
--         DO 103 I=2,IDO,2
--            TI1 = CC(I,1,K)-CC(I,3,K)
--            TI2 = CC(I,1,K)+CC(I,3,K)
--            TI3 = CC(I,2,K)+CC(I,4,K)
--            TR4 = CC(I,4,K)-CC(I,2,K)
--            TR1 = CC(I-1,1,K)-CC(I-1,3,K)
--            TR2 = CC(I-1,1,K)+CC(I-1,3,K)
--            TI4 = CC(I-1,2,K)-CC(I-1,4,K)
--            TR3 = CC(I-1,2,K)+CC(I-1,4,K)
--            CH(I-1,K,1) = TR2+TR3
--            CR3 = TR2-TR3
--            CH(I,K,1) = TI2+TI3
--            CI3 = TI2-TI3
--            CR2 = TR1+TR4
--            CR4 = TR1-TR4
--            CI2 = TI1+TI4
--            CI4 = TI1-TI4
--            CH(I-1,K,2) = WA1(I-1)*CR2-WA1(I)*CI2
--            CH(I,K,2) = WA1(I-1)*CI2+WA1(I)*CR2
--            CH(I-1,K,3) = WA2(I-1)*CR3-WA2(I)*CI3
--            CH(I,K,3) = WA2(I-1)*CI3+WA2(I)*CR3
--            CH(I-1,K,4) = WA3(I-1)*CR4-WA3(I)*CI4
--            CH(I,K,4) = WA3(I-1)*CI4+WA3(I)*CR4
--  103    CONTINUE
--  104 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DPASSB5 (IDO,L1,CC,CH,WA1,WA2,WA3,WA4)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,5,L1)           ,CH(IDO,L1,5)           ,
--     1                WA1(*)     ,WA2(*)     ,WA3(*)     ,WA4(*)
--      DATA TR11,TI11,TR12,TI12 /
--     1   .30901699437494742410229341718281905D0,
--     2   .95105651629515357211643933337938214D0,
--     3  -.80901699437494742410229341718281906D0,
--     4   .58778525229247312916870595463907276D0/
--      IF (IDO .NE. 2) GO TO 102
--      DO 101 K=1,L1
--         TI5 = CC(2,2,K)-CC(2,5,K)
--         TI2 = CC(2,2,K)+CC(2,5,K)
--         TI4 = CC(2,3,K)-CC(2,4,K)
--         TI3 = CC(2,3,K)+CC(2,4,K)
--         TR5 = CC(1,2,K)-CC(1,5,K)
--         TR2 = CC(1,2,K)+CC(1,5,K)
--         TR4 = CC(1,3,K)-CC(1,4,K)
--         TR3 = CC(1,3,K)+CC(1,4,K)
--         CH(1,K,1) = CC(1,1,K)+TR2+TR3
--         CH(2,K,1) = CC(2,1,K)+TI2+TI3
--         CR2 = CC(1,1,K)+TR11*TR2+TR12*TR3
--         CI2 = CC(2,1,K)+TR11*TI2+TR12*TI3
--         CR3 = CC(1,1,K)+TR12*TR2+TR11*TR3
--         CI3 = CC(2,1,K)+TR12*TI2+TR11*TI3
--         CR5 = TI11*TR5+TI12*TR4
--         CI5 = TI11*TI5+TI12*TI4
--         CR4 = TI12*TR5-TI11*TR4
--         CI4 = TI12*TI5-TI11*TI4
--         CH(1,K,2) = CR2-CI5
--         CH(1,K,5) = CR2+CI5
--         CH(2,K,2) = CI2+CR5
--         CH(2,K,3) = CI3+CR4
--         CH(1,K,3) = CR3-CI4
--         CH(1,K,4) = CR3+CI4
--         CH(2,K,4) = CI3-CR4
--         CH(2,K,5) = CI2-CR5
--  101 CONTINUE
--      RETURN
--  102 DO 104 K=1,L1
--         DO 103 I=2,IDO,2
--            TI5 = CC(I,2,K)-CC(I,5,K)
--            TI2 = CC(I,2,K)+CC(I,5,K)
--            TI4 = CC(I,3,K)-CC(I,4,K)
--            TI3 = CC(I,3,K)+CC(I,4,K)
--            TR5 = CC(I-1,2,K)-CC(I-1,5,K)
--            TR2 = CC(I-1,2,K)+CC(I-1,5,K)
--            TR4 = CC(I-1,3,K)-CC(I-1,4,K)
--            TR3 = CC(I-1,3,K)+CC(I-1,4,K)
--            CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3
--            CH(I,K,1) = CC(I,1,K)+TI2+TI3
--            CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3
--            CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3
--            CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3
--            CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3
--            CR5 = TI11*TR5+TI12*TR4
--            CI5 = TI11*TI5+TI12*TI4
--            CR4 = TI12*TR5-TI11*TR4
--            CI4 = TI12*TI5-TI11*TI4
--            DR3 = CR3-CI4
--            DR4 = CR3+CI4
--            DI3 = CI3+CR4
--            DI4 = CI3-CR4
--            DR5 = CR2+CI5
--            DR2 = CR2-CI5
--            DI5 = CI2-CR5
--            DI2 = CI2+CR5
--            CH(I-1,K,2) = WA1(I-1)*DR2-WA1(I)*DI2
--            CH(I,K,2) = WA1(I-1)*DI2+WA1(I)*DR2
--            CH(I-1,K,3) = WA2(I-1)*DR3-WA2(I)*DI3
--            CH(I,K,3) = WA2(I-1)*DI3+WA2(I)*DR3
--            CH(I-1,K,4) = WA3(I-1)*DR4-WA3(I)*DI4
--            CH(I,K,4) = WA3(I-1)*DI4+WA3(I)*DR4
--            CH(I-1,K,5) = WA4(I-1)*DR5-WA4(I)*DI5
--            CH(I,K,5) = WA4(I-1)*DI5+WA4(I)*DR5
--  103    CONTINUE
--  104 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DPASSF (NAC,IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CH(IDO,L1,IP)          ,CC(IDO,IP,L1)          ,
--     1                C1(IDO,L1,IP)          ,WA(*)      ,C2(IDL1,IP),
--     2                CH2(IDL1,IP)
--      IDOT = IDO/2
--      NT = IP*IDL1
--      IPP2 = IP+2
--      IPPH = (IP+1)/2
--      IDP = IP*IDO
--C
--      IF (IDO .LT. L1) GO TO 106
--      DO 103 J=2,IPPH
--         JC = IPP2-J
--         DO 102 K=1,L1
--            DO 101 I=1,IDO
--               CH(I,K,J) = CC(I,J,K)+CC(I,JC,K)
--               CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K)
--  101       CONTINUE
--  102    CONTINUE
--  103 CONTINUE
--      DO 105 K=1,L1
--         DO 104 I=1,IDO
--            CH(I,K,1) = CC(I,1,K)
--  104    CONTINUE
--  105 CONTINUE
--      GO TO 112
--  106 DO 109 J=2,IPPH
--         JC = IPP2-J
--         DO 108 I=1,IDO
--            DO 107 K=1,L1
--               CH(I,K,J) = CC(I,J,K)+CC(I,JC,K)
--               CH(I,K,JC) = CC(I,J,K)-CC(I,JC,K)
--  107       CONTINUE
--  108    CONTINUE
--  109 CONTINUE
--      DO 111 I=1,IDO
--         DO 110 K=1,L1
--            CH(I,K,1) = CC(I,1,K)
--  110    CONTINUE
--  111 CONTINUE
--  112 IDL = 2-IDO
--      INC = 0
--      DO 116 L=2,IPPH
--         LC = IPP2-L
--         IDL = IDL+IDO
--         DO 113 IK=1,IDL1
--            C2(IK,L) = CH2(IK,1)+WA(IDL-1)*CH2(IK,2)
--            C2(IK,LC) = -WA(IDL)*CH2(IK,IP)
--  113    CONTINUE
--         IDLJ = IDL
--         INC = INC+IDO
--         DO 115 J=3,IPPH
--            JC = IPP2-J
--            IDLJ = IDLJ+INC
--            IF (IDLJ .GT. IDP) IDLJ = IDLJ-IDP
--            WAR = WA(IDLJ-1)
--            WAI = WA(IDLJ)
--            DO 114 IK=1,IDL1
--               C2(IK,L) = C2(IK,L)+WAR*CH2(IK,J)
--               C2(IK,LC) = C2(IK,LC)-WAI*CH2(IK,JC)
--  114       CONTINUE
--  115    CONTINUE
--  116 CONTINUE
--      DO 118 J=2,IPPH
--         DO 117 IK=1,IDL1
--            CH2(IK,1) = CH2(IK,1)+CH2(IK,J)
--  117    CONTINUE
--  118 CONTINUE
--      DO 120 J=2,IPPH
--         JC = IPP2-J
--         DO 119 IK=2,IDL1,2
--            CH2(IK-1,J) = C2(IK-1,J)-C2(IK,JC)
--            CH2(IK-1,JC) = C2(IK-1,J)+C2(IK,JC)
--            CH2(IK,J) = C2(IK,J)+C2(IK-1,JC)
--            CH2(IK,JC) = C2(IK,J)-C2(IK-1,JC)
--  119    CONTINUE
--  120 CONTINUE
--      NAC = 1
--      IF (IDO .EQ. 2) RETURN
--      NAC = 0
--      DO 121 IK=1,IDL1
--         C2(IK,1) = CH2(IK,1)
--  121 CONTINUE
--      DO 123 J=2,IP
--         DO 122 K=1,L1
--            C1(1,K,J) = CH(1,K,J)
--            C1(2,K,J) = CH(2,K,J)
--  122    CONTINUE
--  123 CONTINUE
--      IF (IDOT .GT. L1) GO TO 127
--      IDIJ = 0
--      DO 126 J=2,IP
--         IDIJ = IDIJ+2
--         DO 125 I=4,IDO,2
--            IDIJ = IDIJ+2
--            DO 124 K=1,L1
--               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)+WA(IDIJ)*CH(I,K,J)
--               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)-WA(IDIJ)*CH(I-1,K,J)
--  124       CONTINUE
--  125    CONTINUE
--  126 CONTINUE
--      RETURN
--  127 IDJ = 2-IDO
--      DO 130 J=2,IP
--         IDJ = IDJ+IDO
--         DO 129 K=1,L1
--            IDIJ = IDJ
--            DO 128 I=4,IDO,2
--               IDIJ = IDIJ+2
--               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)+WA(IDIJ)*CH(I,K,J)
--               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)-WA(IDIJ)*CH(I-1,K,J)
--  128       CONTINUE
--  129    CONTINUE
--  130 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DPASSF2 (IDO,L1,CC,CH,WA1)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,2,L1)           ,CH(IDO,L1,2)           ,
--     1                WA1(*)
--      IF (IDO .GT. 2) GO TO 102
--      DO 101 K=1,L1
--         CH(1,K,1) = CC(1,1,K)+CC(1,2,K)
--         CH(1,K,2) = CC(1,1,K)-CC(1,2,K)
--         CH(2,K,1) = CC(2,1,K)+CC(2,2,K)
--         CH(2,K,2) = CC(2,1,K)-CC(2,2,K)
--  101 CONTINUE
--      RETURN
--  102 DO 104 K=1,L1
--         DO 103 I=2,IDO,2
--            CH(I-1,K,1) = CC(I-1,1,K)+CC(I-1,2,K)
--            TR2 = CC(I-1,1,K)-CC(I-1,2,K)
--            CH(I,K,1) = CC(I,1,K)+CC(I,2,K)
--            TI2 = CC(I,1,K)-CC(I,2,K)
--            CH(I,K,2) = WA1(I-1)*TI2-WA1(I)*TR2
--            CH(I-1,K,2) = WA1(I-1)*TR2+WA1(I)*TI2
--  103    CONTINUE
--  104 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DPASSF3 (IDO,L1,CC,CH,WA1,WA2)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,3,L1)           ,CH(IDO,L1,3)           ,
--     1                WA1(*)     ,WA2(*)
--      DATA TAUR,TAUI /-.5D0,-.86602540378443864676372317075293618D0/
--      IF (IDO .NE. 2) GO TO 102
--      DO 101 K=1,L1
--         TR2 = CC(1,2,K)+CC(1,3,K)
--         CR2 = CC(1,1,K)+TAUR*TR2
--         CH(1,K,1) = CC(1,1,K)+TR2
--         TI2 = CC(2,2,K)+CC(2,3,K)
--         CI2 = CC(2,1,K)+TAUR*TI2
--         CH(2,K,1) = CC(2,1,K)+TI2
--         CR3 = TAUI*(CC(1,2,K)-CC(1,3,K))
--         CI3 = TAUI*(CC(2,2,K)-CC(2,3,K))
--         CH(1,K,2) = CR2-CI3
--         CH(1,K,3) = CR2+CI3
--         CH(2,K,2) = CI2+CR3
--         CH(2,K,3) = CI2-CR3
--  101 CONTINUE
--      RETURN
--  102 DO 104 K=1,L1
--         DO 103 I=2,IDO,2
--            TR2 = CC(I-1,2,K)+CC(I-1,3,K)
--            CR2 = CC(I-1,1,K)+TAUR*TR2
--            CH(I-1,K,1) = CC(I-1,1,K)+TR2
--            TI2 = CC(I,2,K)+CC(I,3,K)
--            CI2 = CC(I,1,K)+TAUR*TI2
--            CH(I,K,1) = CC(I,1,K)+TI2
--            CR3 = TAUI*(CC(I-1,2,K)-CC(I-1,3,K))
--            CI3 = TAUI*(CC(I,2,K)-CC(I,3,K))
--            DR2 = CR2-CI3
--            DR3 = CR2+CI3
--            DI2 = CI2+CR3
--            DI3 = CI2-CR3
--            CH(I,K,2) = WA1(I-1)*DI2-WA1(I)*DR2
--            CH(I-1,K,2) = WA1(I-1)*DR2+WA1(I)*DI2
--            CH(I,K,3) = WA2(I-1)*DI3-WA2(I)*DR3
--            CH(I-1,K,3) = WA2(I-1)*DR3+WA2(I)*DI3
--  103    CONTINUE
--  104 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DPASSF4 (IDO,L1,CC,CH,WA1,WA2,WA3)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,4,L1)           ,CH(IDO,L1,4)           ,
--     1                WA1(*)     ,WA2(*)     ,WA3(*)
--      IF (IDO .NE. 2) GO TO 102
--      DO 101 K=1,L1
--         TI1 = CC(2,1,K)-CC(2,3,K)
--         TI2 = CC(2,1,K)+CC(2,3,K)
--         TR4 = CC(2,2,K)-CC(2,4,K)
--         TI3 = CC(2,2,K)+CC(2,4,K)
--         TR1 = CC(1,1,K)-CC(1,3,K)
--         TR2 = CC(1,1,K)+CC(1,3,K)
--         TI4 = CC(1,4,K)-CC(1,2,K)
--         TR3 = CC(1,2,K)+CC(1,4,K)
--         CH(1,K,1) = TR2+TR3
--         CH(1,K,3) = TR2-TR3
--         CH(2,K,1) = TI2+TI3
--         CH(2,K,3) = TI2-TI3
--         CH(1,K,2) = TR1+TR4
--         CH(1,K,4) = TR1-TR4
--         CH(2,K,2) = TI1+TI4
--         CH(2,K,4) = TI1-TI4
--  101 CONTINUE
--      RETURN
--  102 DO 104 K=1,L1
--         DO 103 I=2,IDO,2
--            TI1 = CC(I,1,K)-CC(I,3,K)
--            TI2 = CC(I,1,K)+CC(I,3,K)
--            TI3 = CC(I,2,K)+CC(I,4,K)
--            TR4 = CC(I,2,K)-CC(I,4,K)
--            TR1 = CC(I-1,1,K)-CC(I-1,3,K)
--            TR2 = CC(I-1,1,K)+CC(I-1,3,K)
--            TI4 = CC(I-1,4,K)-CC(I-1,2,K)
--            TR3 = CC(I-1,2,K)+CC(I-1,4,K)
--            CH(I-1,K,1) = TR2+TR3
--            CR3 = TR2-TR3
--            CH(I,K,1) = TI2+TI3
--            CI3 = TI2-TI3
--            CR2 = TR1+TR4
--            CR4 = TR1-TR4
--            CI2 = TI1+TI4
--            CI4 = TI1-TI4
--            CH(I-1,K,2) = WA1(I-1)*CR2+WA1(I)*CI2
--            CH(I,K,2) = WA1(I-1)*CI2-WA1(I)*CR2
--            CH(I-1,K,3) = WA2(I-1)*CR3+WA2(I)*CI3
--            CH(I,K,3) = WA2(I-1)*CI3-WA2(I)*CR3
--            CH(I-1,K,4) = WA3(I-1)*CR4+WA3(I)*CI4
--            CH(I,K,4) = WA3(I-1)*CI4-WA3(I)*CR4
--  103    CONTINUE
--  104 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DPASSF5 (IDO,L1,CC,CH,WA1,WA2,WA3,WA4)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,5,L1)           ,CH(IDO,L1,5)           ,
--     1                WA1(*)     ,WA2(*)     ,WA3(*)     ,WA4(*)
--      DATA TR11,TI11,TR12,TI12 /
--     1   .30901699437494742410229341718281905D0,
--     2  -.95105651629515357211643933337938214D0,
--     3  -.80901699437494742410229341718281906D0,
--     4  -.58778525229247312916870595463907276D0/
--      IF (IDO .NE. 2) GO TO 102
--      DO 101 K=1,L1
--         TI5 = CC(2,2,K)-CC(2,5,K)
--         TI2 = CC(2,2,K)+CC(2,5,K)
--         TI4 = CC(2,3,K)-CC(2,4,K)
--         TI3 = CC(2,3,K)+CC(2,4,K)
--         TR5 = CC(1,2,K)-CC(1,5,K)
--         TR2 = CC(1,2,K)+CC(1,5,K)
--         TR4 = CC(1,3,K)-CC(1,4,K)
--         TR3 = CC(1,3,K)+CC(1,4,K)
--         CH(1,K,1) = CC(1,1,K)+TR2+TR3
--         CH(2,K,1) = CC(2,1,K)+TI2+TI3
--         CR2 = CC(1,1,K)+TR11*TR2+TR12*TR3
--         CI2 = CC(2,1,K)+TR11*TI2+TR12*TI3
--         CR3 = CC(1,1,K)+TR12*TR2+TR11*TR3
--         CI3 = CC(2,1,K)+TR12*TI2+TR11*TI3
--         CR5 = TI11*TR5+TI12*TR4
--         CI5 = TI11*TI5+TI12*TI4
--         CR4 = TI12*TR5-TI11*TR4
--         CI4 = TI12*TI5-TI11*TI4
--         CH(1,K,2) = CR2-CI5
--         CH(1,K,5) = CR2+CI5
--         CH(2,K,2) = CI2+CR5
--         CH(2,K,3) = CI3+CR4
--         CH(1,K,3) = CR3-CI4
--         CH(1,K,4) = CR3+CI4
--         CH(2,K,4) = CI3-CR4
--         CH(2,K,5) = CI2-CR5
--  101 CONTINUE
--      RETURN
--  102 DO 104 K=1,L1
--         DO 103 I=2,IDO,2
--            TI5 = CC(I,2,K)-CC(I,5,K)
--            TI2 = CC(I,2,K)+CC(I,5,K)
--            TI4 = CC(I,3,K)-CC(I,4,K)
--            TI3 = CC(I,3,K)+CC(I,4,K)
--            TR5 = CC(I-1,2,K)-CC(I-1,5,K)
--            TR2 = CC(I-1,2,K)+CC(I-1,5,K)
--            TR4 = CC(I-1,3,K)-CC(I-1,4,K)
--            TR3 = CC(I-1,3,K)+CC(I-1,4,K)
--            CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3
--            CH(I,K,1) = CC(I,1,K)+TI2+TI3
--            CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3
--            CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3
--            CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3
--            CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3
--            CR5 = TI11*TR5+TI12*TR4
--            CI5 = TI11*TI5+TI12*TI4
--            CR4 = TI12*TR5-TI11*TR4
--            CI4 = TI12*TI5-TI11*TI4
--            DR3 = CR3-CI4
--            DR4 = CR3+CI4
--            DI3 = CI3+CR4
--            DI4 = CI3-CR4
--            DR5 = CR2+CI5
--            DR2 = CR2-CI5
--            DI5 = CI2-CR5
--            DI2 = CI2+CR5
--            CH(I-1,K,2) = WA1(I-1)*DR2+WA1(I)*DI2
--            CH(I,K,2) = WA1(I-1)*DI2-WA1(I)*DR2
--            CH(I-1,K,3) = WA2(I-1)*DR3+WA2(I)*DI3
--            CH(I,K,3) = WA2(I-1)*DI3-WA2(I)*DR3
--            CH(I-1,K,4) = WA3(I-1)*DR4+WA3(I)*DI4
--            CH(I,K,4) = WA3(I-1)*DI4-WA3(I)*DR4
--            CH(I-1,K,5) = WA4(I-1)*DR5+WA4(I)*DI5
--            CH(I,K,5) = WA4(I-1)*DI5-WA4(I)*DR5
--  103    CONTINUE
--  104 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DRADB2 (IDO,L1,CC,CH,WA1)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,2,L1)           ,CH(IDO,L1,2)           ,
--     1                WA1(*)
--      DO 101 K=1,L1
--         CH(1,K,1) = CC(1,1,K)+CC(IDO,2,K)
--         CH(1,K,2) = CC(1,1,K)-CC(IDO,2,K)
--  101 CONTINUE
--      IF (IDO-2) 107,105,102
--  102 IDP2 = IDO+2
--      DO 104 K=1,L1
--         DO 103 I=3,IDO,2
--            IC = IDP2-I
--            CH(I-1,K,1) = CC(I-1,1,K)+CC(IC-1,2,K)
--            TR2 = CC(I-1,1,K)-CC(IC-1,2,K)
--            CH(I,K,1) = CC(I,1,K)-CC(IC,2,K)
--            TI2 = CC(I,1,K)+CC(IC,2,K)
--            CH(I-1,K,2) = WA1(I-2)*TR2-WA1(I-1)*TI2
--            CH(I,K,2) = WA1(I-2)*TI2+WA1(I-1)*TR2
--  103    CONTINUE
--  104 CONTINUE
--      IF (MOD(IDO,2) .EQ. 1) RETURN
--  105 DO 106 K=1,L1
--         CH(IDO,K,1) = CC(IDO,1,K)+CC(IDO,1,K)
--         CH(IDO,K,2) = -(CC(1,2,K)+CC(1,2,K))
--  106 CONTINUE
--  107 RETURN
--      END
--      SUBROUTINE DRADB3 (IDO,L1,CC,CH,WA1,WA2)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,3,L1)           ,CH(IDO,L1,3)           ,
--     1                WA1(*)     ,WA2(*)
--      DATA TAUR,TAUI /-.5D0,.86602540378443864676372317075293618D0/
--      DO 101 K=1,L1
--         TR2 = CC(IDO,2,K)+CC(IDO,2,K)
--         CR2 = CC(1,1,K)+TAUR*TR2
--         CH(1,K,1) = CC(1,1,K)+TR2
--         CI3 = TAUI*(CC(1,3,K)+CC(1,3,K))
--         CH(1,K,2) = CR2-CI3
--         CH(1,K,3) = CR2+CI3
--  101 CONTINUE
--      IF (IDO .EQ. 1) RETURN
--      IDP2 = IDO+2
--      DO 103 K=1,L1
--         DO 102 I=3,IDO,2
--            IC = IDP2-I
--            TR2 = CC(I-1,3,K)+CC(IC-1,2,K)
--            CR2 = CC(I-1,1,K)+TAUR*TR2
--            CH(I-1,K,1) = CC(I-1,1,K)+TR2
--            TI2 = CC(I,3,K)-CC(IC,2,K)
--            CI2 = CC(I,1,K)+TAUR*TI2
--            CH(I,K,1) = CC(I,1,K)+TI2
--            CR3 = TAUI*(CC(I-1,3,K)-CC(IC-1,2,K))
--            CI3 = TAUI*(CC(I,3,K)+CC(IC,2,K))
--            DR2 = CR2-CI3
--            DR3 = CR2+CI3
--            DI2 = CI2+CR3
--            DI3 = CI2-CR3
--            CH(I-1,K,2) = WA1(I-2)*DR2-WA1(I-1)*DI2
--            CH(I,K,2) = WA1(I-2)*DI2+WA1(I-1)*DR2
--            CH(I-1,K,3) = WA2(I-2)*DR3-WA2(I-1)*DI3
--            CH(I,K,3) = WA2(I-2)*DI3+WA2(I-1)*DR3
--  102    CONTINUE
--  103 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DRADB4 (IDO,L1,CC,CH,WA1,WA2,WA3)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,4,L1)           ,CH(IDO,L1,4)           ,
--     1                WA1(*)     ,WA2(*)     ,WA3(*)
--      DATA SQRT2 /1.4142135623730950488016887242096980D0/
--      DO 101 K=1,L1
--         TR1 = CC(1,1,K)-CC(IDO,4,K)
--         TR2 = CC(1,1,K)+CC(IDO,4,K)
--         TR3 = CC(IDO,2,K)+CC(IDO,2,K)
--         TR4 = CC(1,3,K)+CC(1,3,K)
--         CH(1,K,1) = TR2+TR3
--         CH(1,K,2) = TR1-TR4
--         CH(1,K,3) = TR2-TR3
--         CH(1,K,4) = TR1+TR4
--  101 CONTINUE
--      IF (IDO-2) 107,105,102
--  102 IDP2 = IDO+2
--      DO 104 K=1,L1
--         DO 103 I=3,IDO,2
--            IC = IDP2-I
--            TI1 = CC(I,1,K)+CC(IC,4,K)
--            TI2 = CC(I,1,K)-CC(IC,4,K)
--            TI3 = CC(I,3,K)-CC(IC,2,K)
--            TR4 = CC(I,3,K)+CC(IC,2,K)
--            TR1 = CC(I-1,1,K)-CC(IC-1,4,K)
--            TR2 = CC(I-1,1,K)+CC(IC-1,4,K)
--            TI4 = CC(I-1,3,K)-CC(IC-1,2,K)
--            TR3 = CC(I-1,3,K)+CC(IC-1,2,K)
--            CH(I-1,K,1) = TR2+TR3
--            CR3 = TR2-TR3
--            CH(I,K,1) = TI2+TI3
--            CI3 = TI2-TI3
--            CR2 = TR1-TR4
--            CR4 = TR1+TR4
--            CI2 = TI1+TI4
--            CI4 = TI1-TI4
--            CH(I-1,K,2) = WA1(I-2)*CR2-WA1(I-1)*CI2
--            CH(I,K,2) = WA1(I-2)*CI2+WA1(I-1)*CR2
--            CH(I-1,K,3) = WA2(I-2)*CR3-WA2(I-1)*CI3
--            CH(I,K,3) = WA2(I-2)*CI3+WA2(I-1)*CR3
--            CH(I-1,K,4) = WA3(I-2)*CR4-WA3(I-1)*CI4
--            CH(I,K,4) = WA3(I-2)*CI4+WA3(I-1)*CR4
--  103    CONTINUE
--  104 CONTINUE
--      IF (MOD(IDO,2) .EQ. 1) RETURN
--  105 CONTINUE
--      DO 106 K=1,L1
--         TI1 = CC(1,2,K)+CC(1,4,K)
--         TI2 = CC(1,4,K)-CC(1,2,K)
--         TR1 = CC(IDO,1,K)-CC(IDO,3,K)
--         TR2 = CC(IDO,1,K)+CC(IDO,3,K)
--         CH(IDO,K,1) = TR2+TR2
--         CH(IDO,K,2) = SQRT2*(TR1-TI1)
--         CH(IDO,K,3) = TI2+TI2
--         CH(IDO,K,4) = -SQRT2*(TR1+TI1)
--  106 CONTINUE
--  107 RETURN
--      END
--      SUBROUTINE DRADB5 (IDO,L1,CC,CH,WA1,WA2,WA3,WA4)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,5,L1)           ,CH(IDO,L1,5)           ,
--     1                WA1(*)     ,WA2(*)     ,WA3(*)     ,WA4(*)
--      DATA TR11,TI11,TR12,TI12 /
--     1   .30901699437494742410229341718281905D0,
--     2   .95105651629515357211643933337938214D0,
--     3  -.80901699437494742410229341718281906D0,
--     4   .58778525229247312916870595463907276D0/
--      DO 101 K=1,L1
--         TI5 = CC(1,3,K)+CC(1,3,K)
--         TI4 = CC(1,5,K)+CC(1,5,K)
--         TR2 = CC(IDO,2,K)+CC(IDO,2,K)
--         TR3 = CC(IDO,4,K)+CC(IDO,4,K)
--         CH(1,K,1) = CC(1,1,K)+TR2+TR3
--         CR2 = CC(1,1,K)+TR11*TR2+TR12*TR3
--         CR3 = CC(1,1,K)+TR12*TR2+TR11*TR3
--         CI5 = TI11*TI5+TI12*TI4
--         CI4 = TI12*TI5-TI11*TI4
--         CH(1,K,2) = CR2-CI5
--         CH(1,K,3) = CR3-CI4
--         CH(1,K,4) = CR3+CI4
--         CH(1,K,5) = CR2+CI5
--  101 CONTINUE
--      IF (IDO .EQ. 1) RETURN
--      IDP2 = IDO+2
--      DO 103 K=1,L1
--         DO 102 I=3,IDO,2
--            IC = IDP2-I
--            TI5 = CC(I,3,K)+CC(IC,2,K)
--            TI2 = CC(I,3,K)-CC(IC,2,K)
--            TI4 = CC(I,5,K)+CC(IC,4,K)
--            TI3 = CC(I,5,K)-CC(IC,4,K)
--            TR5 = CC(I-1,3,K)-CC(IC-1,2,K)
--            TR2 = CC(I-1,3,K)+CC(IC-1,2,K)
--            TR4 = CC(I-1,5,K)-CC(IC-1,4,K)
--            TR3 = CC(I-1,5,K)+CC(IC-1,4,K)
--            CH(I-1,K,1) = CC(I-1,1,K)+TR2+TR3
--            CH(I,K,1) = CC(I,1,K)+TI2+TI3
--            CR2 = CC(I-1,1,K)+TR11*TR2+TR12*TR3
--            CI2 = CC(I,1,K)+TR11*TI2+TR12*TI3
--            CR3 = CC(I-1,1,K)+TR12*TR2+TR11*TR3
--            CI3 = CC(I,1,K)+TR12*TI2+TR11*TI3
--            CR5 = TI11*TR5+TI12*TR4
--            CI5 = TI11*TI5+TI12*TI4
--            CR4 = TI12*TR5-TI11*TR4
--            CI4 = TI12*TI5-TI11*TI4
--            DR3 = CR3-CI4
--            DR4 = CR3+CI4
--            DI3 = CI3+CR4
--            DI4 = CI3-CR4
--            DR5 = CR2+CI5
--            DR2 = CR2-CI5
--            DI5 = CI2-CR5
--            DI2 = CI2+CR5
--            CH(I-1,K,2) = WA1(I-2)*DR2-WA1(I-1)*DI2
--            CH(I,K,2) = WA1(I-2)*DI2+WA1(I-1)*DR2
--            CH(I-1,K,3) = WA2(I-2)*DR3-WA2(I-1)*DI3
--            CH(I,K,3) = WA2(I-2)*DI3+WA2(I-1)*DR3
--            CH(I-1,K,4) = WA3(I-2)*DR4-WA3(I-1)*DI4
--            CH(I,K,4) = WA3(I-2)*DI4+WA3(I-1)*DR4
--            CH(I-1,K,5) = WA4(I-2)*DR5-WA4(I-1)*DI5
--            CH(I,K,5) = WA4(I-2)*DI5+WA4(I-1)*DR5
--  102    CONTINUE
--  103 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DRADBG (IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CH(IDO,L1,IP)          ,CC(IDO,IP,L1)          ,
--     1                C1(IDO,L1,IP)          ,C2(IDL1,IP),
--     2                CH2(IDL1,IP)           ,WA(*)
--      DATA TPI/6.2831853071795864769252867665590057D0/
--      ARG = TPI/DBLE(IP)
--      DCP = DCOS(ARG)
--      DSP = DSIN(ARG)
--      IDP2 = IDO+2
--      NBD = (IDO-1)/2
--      IPP2 = IP+2
--      IPPH = (IP+1)/2
--      IF (IDO .LT. L1) GO TO 103
--      DO 102 K=1,L1
--         DO 101 I=1,IDO
--            CH(I,K,1) = CC(I,1,K)
--  101    CONTINUE
--  102 CONTINUE
--      GO TO 106
--  103 DO 105 I=1,IDO
--         DO 104 K=1,L1
--            CH(I,K,1) = CC(I,1,K)
--  104    CONTINUE
--  105 CONTINUE
--  106 DO 108 J=2,IPPH
--         JC = IPP2-J
--         J2 = J+J
--         DO 107 K=1,L1
--            CH(1,K,J) = CC(IDO,J2-2,K)+CC(IDO,J2-2,K)
--            CH(1,K,JC) = CC(1,J2-1,K)+CC(1,J2-1,K)
--  107    CONTINUE
--  108 CONTINUE
--      IF (IDO .EQ. 1) GO TO 116
--      IF (NBD .LT. L1) GO TO 112
--      DO 111 J=2,IPPH
--         JC = IPP2-J
--         DO 110 K=1,L1
--            DO 109 I=3,IDO,2
--               IC = IDP2-I
--               CH(I-1,K,J) = CC(I-1,2*J-1,K)+CC(IC-1,2*J-2,K)
--               CH(I-1,K,JC) = CC(I-1,2*J-1,K)-CC(IC-1,2*J-2,K)
--               CH(I,K,J) = CC(I,2*J-1,K)-CC(IC,2*J-2,K)
--               CH(I,K,JC) = CC(I,2*J-1,K)+CC(IC,2*J-2,K)
--  109       CONTINUE
--  110    CONTINUE
--  111 CONTINUE
--      GO TO 116
--  112 DO 115 J=2,IPPH
--         JC = IPP2-J
--         DO 114 I=3,IDO,2
--            IC = IDP2-I
--            DO 113 K=1,L1
--               CH(I-1,K,J) = CC(I-1,2*J-1,K)+CC(IC-1,2*J-2,K)
--               CH(I-1,K,JC) = CC(I-1,2*J-1,K)-CC(IC-1,2*J-2,K)
--               CH(I,K,J) = CC(I,2*J-1,K)-CC(IC,2*J-2,K)
--               CH(I,K,JC) = CC(I,2*J-1,K)+CC(IC,2*J-2,K)
--  113       CONTINUE
--  114    CONTINUE
--  115 CONTINUE
--  116 AR1 = 1.0D0
--      AI1 = 0.0D0
--      DO 120 L=2,IPPH
--         LC = IPP2-L
--         AR1H = DCP*AR1-DSP*AI1
--         AI1 = DCP*AI1+DSP*AR1
--         AR1 = AR1H
--         DO 117 IK=1,IDL1
--            C2(IK,L) = CH2(IK,1)+AR1*CH2(IK,2)
--            C2(IK,LC) = AI1*CH2(IK,IP)
--  117    CONTINUE
--         DC2 = AR1
--         DS2 = AI1
--         AR2 = AR1
--         AI2 = AI1
--         DO 119 J=3,IPPH
--            JC = IPP2-J
--            AR2H = DC2*AR2-DS2*AI2
--            AI2 = DC2*AI2+DS2*AR2
--            AR2 = AR2H
--            DO 118 IK=1,IDL1
--               C2(IK,L) = C2(IK,L)+AR2*CH2(IK,J)
--               C2(IK,LC) = C2(IK,LC)+AI2*CH2(IK,JC)
--  118       CONTINUE
--  119    CONTINUE
--  120 CONTINUE
--      DO 122 J=2,IPPH
--         DO 121 IK=1,IDL1
--            CH2(IK,1) = CH2(IK,1)+CH2(IK,J)
--  121    CONTINUE
--  122 CONTINUE
--      DO 124 J=2,IPPH
--         JC = IPP2-J
--         DO 123 K=1,L1
--            CH(1,K,J) = C1(1,K,J)-C1(1,K,JC)
--            CH(1,K,JC) = C1(1,K,J)+C1(1,K,JC)
--  123    CONTINUE
--  124 CONTINUE
--      IF (IDO .EQ. 1) GO TO 132
--      IF (NBD .LT. L1) GO TO 128
--      DO 127 J=2,IPPH
--         JC = IPP2-J
--         DO 126 K=1,L1
--            DO 125 I=3,IDO,2
--               CH(I-1,K,J) = C1(I-1,K,J)-C1(I,K,JC)
--               CH(I-1,K,JC) = C1(I-1,K,J)+C1(I,K,JC)
--               CH(I,K,J) = C1(I,K,J)+C1(I-1,K,JC)
--               CH(I,K,JC) = C1(I,K,J)-C1(I-1,K,JC)
--  125       CONTINUE
--  126    CONTINUE
--  127 CONTINUE
--      GO TO 132
--  128 DO 131 J=2,IPPH
--         JC = IPP2-J
--         DO 130 I=3,IDO,2
--            DO 129 K=1,L1
--               CH(I-1,K,J) = C1(I-1,K,J)-C1(I,K,JC)
--               CH(I-1,K,JC) = C1(I-1,K,J)+C1(I,K,JC)
--               CH(I,K,J) = C1(I,K,J)+C1(I-1,K,JC)
--               CH(I,K,JC) = C1(I,K,J)-C1(I-1,K,JC)
--  129       CONTINUE
--  130    CONTINUE
--  131 CONTINUE
--  132 CONTINUE
--      IF (IDO .EQ. 1) RETURN
--      DO 133 IK=1,IDL1
--         C2(IK,1) = CH2(IK,1)
--  133 CONTINUE
--      DO 135 J=2,IP
--         DO 134 K=1,L1
--            C1(1,K,J) = CH(1,K,J)
--  134    CONTINUE
--  135 CONTINUE
--      IF (NBD .GT. L1) GO TO 139
--      IS = -IDO
--      DO 138 J=2,IP
--         IS = IS+IDO
--         IDIJ = IS
--         DO 137 I=3,IDO,2
--            IDIJ = IDIJ+2
--            DO 136 K=1,L1
--               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J)
--               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J)
--  136       CONTINUE
--  137    CONTINUE
--  138 CONTINUE
--      GO TO 143
--  139 IS = -IDO
--      DO 142 J=2,IP
--         IS = IS+IDO
--         DO 141 K=1,L1
--            IDIJ = IS
--            DO 140 I=3,IDO,2
--               IDIJ = IDIJ+2
--               C1(I-1,K,J) = WA(IDIJ-1)*CH(I-1,K,J)-WA(IDIJ)*CH(I,K,J)
--               C1(I,K,J) = WA(IDIJ-1)*CH(I,K,J)+WA(IDIJ)*CH(I-1,K,J)
--  140       CONTINUE
--  141    CONTINUE
--  142 CONTINUE
--  143 RETURN
--      END
--      SUBROUTINE DRADF2 (IDO,L1,CC,CH,WA1)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CH(IDO,2,L1)           ,CC(IDO,L1,2)           ,
--     1                WA1(*)
--      DO 101 K=1,L1
--         CH(1,1,K) = CC(1,K,1)+CC(1,K,2)
--         CH(IDO,2,K) = CC(1,K,1)-CC(1,K,2)
--  101 CONTINUE
--      IF (IDO-2) 107,105,102
--  102 IDP2 = IDO+2
--      DO 104 K=1,L1
--         DO 103 I=3,IDO,2
--            IC = IDP2-I
--            TR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2)
--            TI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2)
--            CH(I,1,K) = CC(I,K,1)+TI2
--            CH(IC,2,K) = TI2-CC(I,K,1)
--            CH(I-1,1,K) = CC(I-1,K,1)+TR2
--            CH(IC-1,2,K) = CC(I-1,K,1)-TR2
--  103    CONTINUE
--  104 CONTINUE
--      IF (MOD(IDO,2) .EQ. 1) RETURN
--  105 DO 106 K=1,L1
--         CH(1,2,K) = -CC(IDO,K,2)
--         CH(IDO,1,K) = CC(IDO,K,1)
--  106 CONTINUE
--  107 RETURN
--      END
--      SUBROUTINE DRADF3 (IDO,L1,CC,CH,WA1,WA2)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CH(IDO,3,L1)           ,CC(IDO,L1,3)           ,
--     1                WA1(*)     ,WA2(*)
--      DATA TAUR,TAUI /-.5D0,.86602540378443864676372317075293618D0/
--      DO 101 K=1,L1
--         CR2 = CC(1,K,2)+CC(1,K,3)
--         CH(1,1,K) = CC(1,K,1)+CR2
--         CH(1,3,K) = TAUI*(CC(1,K,3)-CC(1,K,2))
--         CH(IDO,2,K) = CC(1,K,1)+TAUR*CR2
--  101 CONTINUE
--      IF (IDO .EQ. 1) RETURN
--      IDP2 = IDO+2
--      DO 103 K=1,L1
--         DO 102 I=3,IDO,2
--            IC = IDP2-I
--            DR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2)
--            DI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2)
--            DR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3)
--            DI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3)
--            CR2 = DR2+DR3
--            CI2 = DI2+DI3
--            CH(I-1,1,K) = CC(I-1,K,1)+CR2
--            CH(I,1,K) = CC(I,K,1)+CI2
--            TR2 = CC(I-1,K,1)+TAUR*CR2
--            TI2 = CC(I,K,1)+TAUR*CI2
--            TR3 = TAUI*(DI2-DI3)
--            TI3 = TAUI*(DR3-DR2)
--            CH(I-1,3,K) = TR2+TR3
--            CH(IC-1,2,K) = TR2-TR3
--            CH(I,3,K) = TI2+TI3
--            CH(IC,2,K) = TI3-TI2
--  102    CONTINUE
--  103 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DRADF4 (IDO,L1,CC,CH,WA1,WA2,WA3)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,L1,4)           ,CH(IDO,4,L1)           ,
--     1                WA1(*)     ,WA2(*)     ,WA3(*)
--      DATA HSQT2 /0.70710678118654752440084436210484904D0/
--      DO 101 K=1,L1
--         TR1 = CC(1,K,2)+CC(1,K,4)
--         TR2 = CC(1,K,1)+CC(1,K,3)
--         CH(1,1,K) = TR1+TR2
--         CH(IDO,4,K) = TR2-TR1
--         CH(IDO,2,K) = CC(1,K,1)-CC(1,K,3)
--         CH(1,3,K) = CC(1,K,4)-CC(1,K,2)
--  101 CONTINUE
--      IF (IDO-2) 107,105,102
--  102 IDP2 = IDO+2
--      DO 104 K=1,L1
--         DO 103 I=3,IDO,2
--            IC = IDP2-I
--            CR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2)
--            CI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2)
--            CR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3)
--            CI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3)
--            CR4 = WA3(I-2)*CC(I-1,K,4)+WA3(I-1)*CC(I,K,4)
--            CI4 = WA3(I-2)*CC(I,K,4)-WA3(I-1)*CC(I-1,K,4)
--            TR1 = CR2+CR4
--            TR4 = CR4-CR2
--            TI1 = CI2+CI4
--            TI4 = CI2-CI4
--            TI2 = CC(I,K,1)+CI3
--            TI3 = CC(I,K,1)-CI3
--            TR2 = CC(I-1,K,1)+CR3
--            TR3 = CC(I-1,K,1)-CR3
--            CH(I-1,1,K) = TR1+TR2
--            CH(IC-1,4,K) = TR2-TR1
--            CH(I,1,K) = TI1+TI2
--            CH(IC,4,K) = TI1-TI2
--            CH(I-1,3,K) = TI4+TR3
--            CH(IC-1,2,K) = TR3-TI4
--            CH(I,3,K) = TR4+TI3
--            CH(IC,2,K) = TR4-TI3
--  103    CONTINUE
--  104 CONTINUE
--      IF (MOD(IDO,2) .EQ. 1) RETURN
--  105 CONTINUE
--      DO 106 K=1,L1
--         TI1 = -HSQT2*(CC(IDO,K,2)+CC(IDO,K,4))
--         TR1 = HSQT2*(CC(IDO,K,2)-CC(IDO,K,4))
--         CH(IDO,1,K) = TR1+CC(IDO,K,1)
--         CH(IDO,3,K) = CC(IDO,K,1)-TR1
--         CH(1,2,K) = TI1-CC(IDO,K,3)
--         CH(1,4,K) = TI1+CC(IDO,K,3)
--  106 CONTINUE
--  107 RETURN
--      END
--      SUBROUTINE DRADF5 (IDO,L1,CC,CH,WA1,WA2,WA3,WA4)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CC(IDO,L1,5)           ,CH(IDO,5,L1)           ,
--     1                WA1(*)     ,WA2(*)     ,WA3(*)     ,WA4(*)
--      DATA TR11,TI11,TR12,TI12 /
--     1   .30901699437494742410229341718281905D0,
--     2   .95105651629515357211643933337938214D0,
--     3  -.80901699437494742410229341718281906D0,
--     4   .58778525229247312916870595463907276D0/
--      DO 101 K=1,L1
--         CR2 = CC(1,K,5)+CC(1,K,2)
--         CI5 = CC(1,K,5)-CC(1,K,2)
--         CR3 = CC(1,K,4)+CC(1,K,3)
--         CI4 = CC(1,K,4)-CC(1,K,3)
--         CH(1,1,K) = CC(1,K,1)+CR2+CR3
--         CH(IDO,2,K) = CC(1,K,1)+TR11*CR2+TR12*CR3
--         CH(1,3,K) = TI11*CI5+TI12*CI4
--         CH(IDO,4,K) = CC(1,K,1)+TR12*CR2+TR11*CR3
--         CH(1,5,K) = TI12*CI5-TI11*CI4
--  101 CONTINUE
--      IF (IDO .EQ. 1) RETURN
--      IDP2 = IDO+2
--      DO 103 K=1,L1
--         DO 102 I=3,IDO,2
--            IC = IDP2-I
--            DR2 = WA1(I-2)*CC(I-1,K,2)+WA1(I-1)*CC(I,K,2)
--            DI2 = WA1(I-2)*CC(I,K,2)-WA1(I-1)*CC(I-1,K,2)
--            DR3 = WA2(I-2)*CC(I-1,K,3)+WA2(I-1)*CC(I,K,3)
--            DI3 = WA2(I-2)*CC(I,K,3)-WA2(I-1)*CC(I-1,K,3)
--            DR4 = WA3(I-2)*CC(I-1,K,4)+WA3(I-1)*CC(I,K,4)
--            DI4 = WA3(I-2)*CC(I,K,4)-WA3(I-1)*CC(I-1,K,4)
--            DR5 = WA4(I-2)*CC(I-1,K,5)+WA4(I-1)*CC(I,K,5)
--            DI5 = WA4(I-2)*CC(I,K,5)-WA4(I-1)*CC(I-1,K,5)
--            CR2 = DR2+DR5
--            CI5 = DR5-DR2
--            CR5 = DI2-DI5
--            CI2 = DI2+DI5
--            CR3 = DR3+DR4
--            CI4 = DR4-DR3
--            CR4 = DI3-DI4
--            CI3 = DI3+DI4
--            CH(I-1,1,K) = CC(I-1,K,1)+CR2+CR3
--            CH(I,1,K) = CC(I,K,1)+CI2+CI3
--            TR2 = CC(I-1,K,1)+TR11*CR2+TR12*CR3
--            TI2 = CC(I,K,1)+TR11*CI2+TR12*CI3
--            TR3 = CC(I-1,K,1)+TR12*CR2+TR11*CR3
--            TI3 = CC(I,K,1)+TR12*CI2+TR11*CI3
--            TR5 = TI11*CR5+TI12*CR4
--            TI5 = TI11*CI5+TI12*CI4
--            TR4 = TI12*CR5-TI11*CR4
--            TI4 = TI12*CI5-TI11*CI4
--            CH(I-1,3,K) = TR2+TR5
--            CH(IC-1,2,K) = TR2-TR5
--            CH(I,3,K) = TI2+TI5
--            CH(IC,2,K) = TI5-TI2
--            CH(I-1,5,K) = TR3+TR4
--            CH(IC-1,4,K) = TR3-TR4
--            CH(I,5,K) = TI3+TI4
--            CH(IC,4,K) = TI4-TI3
--  102    CONTINUE
--  103 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DRADFG (IDO,IP,L1,IDL1,CC,C1,C2,CH,CH2,WA)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CH(IDO,L1,IP)          ,CC(IDO,IP,L1)          ,
--     1                C1(IDO,L1,IP)          ,C2(IDL1,IP),
--     2                CH2(IDL1,IP)           ,WA(*)
--      DATA TPI/6.2831853071795864769252867665590057D0/
--      ARG = TPI/DBLE(IP)
--      DCP = DCOS(ARG)
--      DSP = DSIN(ARG)
--      IPPH = (IP+1)/2
--      IPP2 = IP+2
--      IDP2 = IDO+2
--      NBD = (IDO-1)/2
--      IF (IDO .EQ. 1) GO TO 119
--      DO 101 IK=1,IDL1
--         CH2(IK,1) = C2(IK,1)
--  101 CONTINUE
--      DO 103 J=2,IP
--         DO 102 K=1,L1
--            CH(1,K,J) = C1(1,K,J)
--  102    CONTINUE
--  103 CONTINUE
--      IF (NBD .GT. L1) GO TO 107
--      IS = -IDO
--      DO 106 J=2,IP
--         IS = IS+IDO
--         IDIJ = IS
--         DO 105 I=3,IDO,2
--            IDIJ = IDIJ+2
--            DO 104 K=1,L1
--               CH(I-1,K,J) = WA(IDIJ-1)*C1(I-1,K,J)+WA(IDIJ)*C1(I,K,J)
--               CH(I,K,J) = WA(IDIJ-1)*C1(I,K,J)-WA(IDIJ)*C1(I-1,K,J)
--  104       CONTINUE
--  105    CONTINUE
--  106 CONTINUE
--      GO TO 111
--  107 IS = -IDO
--      DO 110 J=2,IP
--         IS = IS+IDO
--         DO 109 K=1,L1
--            IDIJ = IS
--            DO 108 I=3,IDO,2
--               IDIJ = IDIJ+2
--               CH(I-1,K,J) = WA(IDIJ-1)*C1(I-1,K,J)+WA(IDIJ)*C1(I,K,J)
--               CH(I,K,J) = WA(IDIJ-1)*C1(I,K,J)-WA(IDIJ)*C1(I-1,K,J)
--  108       CONTINUE
--  109    CONTINUE
--  110 CONTINUE
--  111 IF (NBD .LT. L1) GO TO 115
--      DO 114 J=2,IPPH
--         JC = IPP2-J
--         DO 113 K=1,L1
--            DO 112 I=3,IDO,2
--               C1(I-1,K,J) = CH(I-1,K,J)+CH(I-1,K,JC)
--               C1(I-1,K,JC) = CH(I,K,J)-CH(I,K,JC)
--               C1(I,K,J) = CH(I,K,J)+CH(I,K,JC)
--               C1(I,K,JC) = CH(I-1,K,JC)-CH(I-1,K,J)
--  112       CONTINUE
--  113    CONTINUE
--  114 CONTINUE
--      GO TO 121
--  115 DO 118 J=2,IPPH
--         JC = IPP2-J
--         DO 117 I=3,IDO,2
--            DO 116 K=1,L1
--               C1(I-1,K,J) = CH(I-1,K,J)+CH(I-1,K,JC)
--               C1(I-1,K,JC) = CH(I,K,J)-CH(I,K,JC)
--               C1(I,K,J) = CH(I,K,J)+CH(I,K,JC)
--               C1(I,K,JC) = CH(I-1,K,JC)-CH(I-1,K,J)
--  116       CONTINUE
--  117    CONTINUE
--  118 CONTINUE
--      GO TO 121
--  119 DO 120 IK=1,IDL1
--         C2(IK,1) = CH2(IK,1)
--  120 CONTINUE
--  121 DO 123 J=2,IPPH
--         JC = IPP2-J
--         DO 122 K=1,L1
--            C1(1,K,J) = CH(1,K,J)+CH(1,K,JC)
--            C1(1,K,JC) = CH(1,K,JC)-CH(1,K,J)
--  122    CONTINUE
--  123 CONTINUE
--C
--      AR1 = 1.0D0
--      AI1 = 0.0D0
--      DO 127 L=2,IPPH
--         LC = IPP2-L
--         AR1H = DCP*AR1-DSP*AI1
--         AI1 = DCP*AI1+DSP*AR1
--         AR1 = AR1H
--         DO 124 IK=1,IDL1
--            CH2(IK,L) = C2(IK,1)+AR1*C2(IK,2)
--            CH2(IK,LC) = AI1*C2(IK,IP)
--  124    CONTINUE
--         DC2 = AR1
--         DS2 = AI1
--         AR2 = AR1
--         AI2 = AI1
--         DO 126 J=3,IPPH
--            JC = IPP2-J
--            AR2H = DC2*AR2-DS2*AI2
--            AI2 = DC2*AI2+DS2*AR2
--            AR2 = AR2H
--            DO 125 IK=1,IDL1
--               CH2(IK,L) = CH2(IK,L)+AR2*C2(IK,J)
--               CH2(IK,LC) = CH2(IK,LC)+AI2*C2(IK,JC)
--  125       CONTINUE
--  126    CONTINUE
--  127 CONTINUE
--      DO 129 J=2,IPPH
--         DO 128 IK=1,IDL1
--            CH2(IK,1) = CH2(IK,1)+C2(IK,J)
--  128    CONTINUE
--  129 CONTINUE
--C
--      IF (IDO .LT. L1) GO TO 132
--      DO 131 K=1,L1
--         DO 130 I=1,IDO
--            CC(I,1,K) = CH(I,K,1)
--  130    CONTINUE
--  131 CONTINUE
--      GO TO 135
--  132 DO 134 I=1,IDO
--         DO 133 K=1,L1
--            CC(I,1,K) = CH(I,K,1)
--  133    CONTINUE
--  134 CONTINUE
--  135 DO 137 J=2,IPPH
--         JC = IPP2-J
--         J2 = J+J
--         DO 136 K=1,L1
--            CC(IDO,J2-2,K) = CH(1,K,J)
--            CC(1,J2-1,K) = CH(1,K,JC)
--  136    CONTINUE
--  137 CONTINUE
--      IF (IDO .EQ. 1) RETURN
--      IF (NBD .LT. L1) GO TO 141
--      DO 140 J=2,IPPH
--         JC = IPP2-J
--         J2 = J+J
--         DO 139 K=1,L1
--            DO 138 I=3,IDO,2
--               IC = IDP2-I
--               CC(I-1,J2-1,K) = CH(I-1,K,J)+CH(I-1,K,JC)
--               CC(IC-1,J2-2,K) = CH(I-1,K,J)-CH(I-1,K,JC)
--               CC(I,J2-1,K) = CH(I,K,J)+CH(I,K,JC)
--               CC(IC,J2-2,K) = CH(I,K,JC)-CH(I,K,J)
--  138       CONTINUE
--  139    CONTINUE
--  140 CONTINUE
--      RETURN
--  141 DO 144 J=2,IPPH
--         JC = IPP2-J
--         J2 = J+J
--         DO 143 I=3,IDO,2
--            IC = IDP2-I
--            DO 142 K=1,L1
--               CC(I-1,J2-1,K) = CH(I-1,K,J)+CH(I-1,K,JC)
--               CC(IC-1,J2-2,K) = CH(I-1,K,J)-CH(I-1,K,JC)
--               CC(I,J2-1,K) = CH(I,K,J)+CH(I,K,JC)
--               CC(IC,J2-2,K) = CH(I,K,JC)-CH(I,K,J)
--  142       CONTINUE
--  143    CONTINUE
--  144 CONTINUE
--      RETURN
--      END
--
--      SUBROUTINE DFFTB1 (N,C,CH,WA,IFAC)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CH(*)      ,C(*)       ,WA(*)      ,IFAC(*)
--      NF = IFAC(2)
--      NA = 0
--      L1 = 1
--      IW = 1
--      DO 116 K1=1,NF
--         IP = IFAC(K1+2)
--         L2 = IP*L1
--         IDO = N/L2
--         IDL1 = IDO*L1
--         IF (IP .NE. 4) GO TO 103
--         IX2 = IW+IDO
--         IX3 = IX2+IDO
--         IF (NA .NE. 0) GO TO 101
--         CALL DRADB4 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3))
--         GO TO 102
--  101    CALL DRADB4 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3))
--  102    NA = 1-NA
--         GO TO 115
--  103    IF (IP .NE. 2) GO TO 106
--         IF (NA .NE. 0) GO TO 104
--         CALL DRADB2 (IDO,L1,C,CH,WA(IW))
--         GO TO 105
--  104    CALL DRADB2 (IDO,L1,CH,C,WA(IW))
--  105    NA = 1-NA
--         GO TO 115
--  106    IF (IP .NE. 3) GO TO 109
--         IX2 = IW+IDO
--         IF (NA .NE. 0) GO TO 107
--         CALL DRADB3 (IDO,L1,C,CH,WA(IW),WA(IX2))
--         GO TO 108
--  107    CALL DRADB3 (IDO,L1,CH,C,WA(IW),WA(IX2))
--  108    NA = 1-NA
--         GO TO 115
--  109    IF (IP .NE. 5) GO TO 112
--         IX2 = IW+IDO
--         IX3 = IX2+IDO
--         IX4 = IX3+IDO
--         IF (NA .NE. 0) GO TO 110
--         CALL DRADB5 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4))
--         GO TO 111
--  110    CALL DRADB5 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4))
--  111    NA = 1-NA
--         GO TO 115
--  112    IF (NA .NE. 0) GO TO 113
--         CALL DRADBG (IDO,IP,L1,IDL1,C,C,C,CH,CH,WA(IW))
--         GO TO 114
--  113    CALL DRADBG (IDO,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW))
--  114    IF (IDO .EQ. 1) NA = 1-NA
--  115    L1 = L2
--         IW = IW+(IP-1)*IDO
--  116 CONTINUE
--      IF (NA .EQ. 0) RETURN
--      DO 117 I=1,N
--         C(I) = CH(I)
--  117 CONTINUE
--      RETURN
--      END
--
--
--      SUBROUTINE DFFTB (N,R,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       R(*)       ,WSAVE(*)
--      IF (N .EQ. 1) RETURN
--      CALL DFFTB1 (N,R,WSAVE,WSAVE(N+1),WSAVE(2*N+1))
--      RETURN
--      END
--
--      SUBROUTINE DFFTF1 (N,C,CH,WA,IFAC)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       CH(*)      ,C(*)       ,WA(*)      ,IFAC(*)
--      NF = IFAC(2)
--      NA = 1
--      L2 = N
--      IW = N
--      DO 111 K1=1,NF
--         KH = NF-K1
--         IP = IFAC(KH+3)
--         L1 = L2/IP
--         IDO = N/L2
--         IDL1 = IDO*L1
--         IW = IW-(IP-1)*IDO
--         NA = 1-NA
--         IF (IP .NE. 4) GO TO 102
--         IX2 = IW+IDO
--         IX3 = IX2+IDO
--         IF (NA .NE. 0) GO TO 101
--         CALL DRADF4 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3))
--         GO TO 110
--  101    CALL DRADF4 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3))
--         GO TO 110
--  102    IF (IP .NE. 2) GO TO 104
--         IF (NA .NE. 0) GO TO 103
--         CALL DRADF2 (IDO,L1,C,CH,WA(IW))
--         GO TO 110
--  103    CALL DRADF2 (IDO,L1,CH,C,WA(IW))
--         GO TO 110
--  104    IF (IP .NE. 3) GO TO 106
--         IX2 = IW+IDO
--         IF (NA .NE. 0) GO TO 105
--         CALL DRADF3 (IDO,L1,C,CH,WA(IW),WA(IX2))
--         GO TO 110
--  105    CALL DRADF3 (IDO,L1,CH,C,WA(IW),WA(IX2))
--         GO TO 110
--  106    IF (IP .NE. 5) GO TO 108
--         IX2 = IW+IDO
--         IX3 = IX2+IDO
--         IX4 = IX3+IDO
--         IF (NA .NE. 0) GO TO 107
--         CALL DRADF5 (IDO,L1,C,CH,WA(IW),WA(IX2),WA(IX3),WA(IX4))
--         GO TO 110
--  107    CALL DRADF5 (IDO,L1,CH,C,WA(IW),WA(IX2),WA(IX3),WA(IX4))
--         GO TO 110
--  108    IF (IDO .EQ. 1) NA = 1-NA
--         IF (NA .NE. 0) GO TO 109
--         CALL DRADFG (IDO,IP,L1,IDL1,C,C,C,CH,CH,WA(IW))
--         NA = 1
--         GO TO 110
--  109    CALL DRADFG (IDO,IP,L1,IDL1,CH,CH,CH,C,C,WA(IW))
--         NA = 0
--  110    L2 = L1
--  111 CONTINUE
--      IF (NA .EQ. 1) RETURN
--      DO 112 I=1,N
--         C(I) = CH(I)
--  112 CONTINUE
--      RETURN
--      END
--
--
--      SUBROUTINE DFFTF (N,R,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       R(*)       ,WSAVE(*)
--      IF (N .EQ. 1) RETURN
--      CALL DFFTF1 (N,R,WSAVE,WSAVE(N+1),WSAVE(2*N+1))
--      RETURN
--      END
--
--      SUBROUTINE DFFTI1 (N,WA,IFAC)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       WA(*)      ,IFAC(*)    ,NTRYH(4)
--      DATA NTRYH(1),NTRYH(2),NTRYH(3),NTRYH(4)/4,2,3,5/
--      NL = N
--      NF = 0
--      J = 0
--  101 J = J+1
--      IF (J-4) 102,102,103
--  102 NTRY = NTRYH(J)
--      GO TO 104
--  103 NTRY = NTRY+2
--  104 NQ = NL/NTRY
--      NR = NL-NTRY*NQ
--      IF (NR) 101,105,101
--  105 NF = NF+1
--      IFAC(NF+2) = NTRY
--      NL = NQ
--      IF (NTRY .NE. 2) GO TO 107
--      IF (NF .EQ. 1) GO TO 107
--      DO 106 I=2,NF
--         IB = NF-I+2
--         IFAC(IB+2) = IFAC(IB+1)
--  106 CONTINUE
--      IFAC(3) = 2
--  107 IF (NL .NE. 1) GO TO 104
--      IFAC(1) = N
--      IFAC(2) = NF
--      TPI = 6.2831853071795864769252867665590057D0
--      ARGH = TPI/DBLE(N)
--      IS = 0
--      NFM1 = NF-1
--      L1 = 1
--      IF (NFM1 .EQ. 0) RETURN
--      DO 110 K1=1,NFM1
--         IP = IFAC(K1+2)
--         LD = 0
--         L2 = L1*IP
--         IDO = N/L2
--         IPM = IP-1
--         DO 109 J=1,IPM
--            LD = LD+L1
--            I = IS
--            ARGLD = DBLE(LD)*ARGH
--            FI = 0.0D0
--            DO 108 II=3,IDO,2
--               I = I+2
--               FI = FI+1.0D0
--               ARG = FI*ARGLD
--               WA(I-1) = DCOS(ARG)
--               WA(I) = DSIN(ARG)
--  108       CONTINUE
--            IS = IS+IDO
--  109    CONTINUE
--         L1 = L2
--  110 CONTINUE
--      RETURN
--      END
--
--      SUBROUTINE DFFTI (N,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       WSAVE(*)
--      IF (N .EQ. 1) RETURN
--      CALL DFFTI1 (N,WSAVE(N+1),WSAVE(2*N+1))
--      RETURN
--      END
--      SUBROUTINE DSINQB (N,X,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       X(*)       ,WSAVE(*)
--      IF (N .GT. 1) GO TO 101
--      X(1) = 4.0D0*X(1)
--      RETURN
--  101 NS2 = N/2
--      DO 102 K=2,N,2
--         X(K) = -X(K)
--  102 CONTINUE
--      CALL DCOSQB (N,X,WSAVE)
--      DO 103 K=1,NS2
--         KC = N-K
--         XHOLD = X(K)
--         X(K) = X(KC+1)
--         X(KC+1) = XHOLD
--  103 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DSINQF (N,X,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       X(*)       ,WSAVE(*)
--      IF (N .EQ. 1) RETURN
--      NS2 = N/2
--      DO 101 K=1,NS2
--         KC = N-K
--         XHOLD = X(K)
--         X(K) = X(KC+1)
--         X(KC+1) = XHOLD
--  101 CONTINUE
--      CALL DCOSQF (N,X,WSAVE)
--      DO 102 K=2,N,2
--         X(K) = -X(K)
--  102 CONTINUE
--      RETURN
--      END
--      SUBROUTINE DSINQI (N,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       WSAVE(*)
--      CALL DCOSQI (N,WSAVE)
--      RETURN
--      END
--
--      SUBROUTINE DSINT1(N,WAR,WAS,XH,X,IFAC)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION WAR(*),WAS(*),X(*),XH(*),IFAC(*)
--      DATA SQRT3 /1.7320508075688772935274463415058723D0/
--      DO 100 I=1,N
--      XH(I) = WAR(I)
--      WAR(I) = X(I)
--  100 CONTINUE
--      IF (N-2) 101,102,103
--  101 XH(1) = XH(1)+XH(1)
--      GO TO 106
--  102 XHOLD = SQRT3*(XH(1)+XH(2))
--      XH(2) = SQRT3*(XH(1)-XH(2))
--      XH(1) = XHOLD
--      GO TO 106
--  103 NP1 = N+1
--      NS2 = N/2
--      X(1) = 0.0D0
--      DO 104 K=1,NS2
--         KC = NP1-K
--         T1 = XH(K)-XH(KC)
--         T2 = WAS(K)*(XH(K)+XH(KC))
--         X(K+1) = T1+T2
--         X(KC+1) = T2-T1
--  104 CONTINUE
--      MODN = MOD(N,2)
--      IF (MODN .NE. 0) X(NS2+2) = 4.0D0*XH(NS2+1)
--      CALL DFFTF1 (NP1,X,XH,WAR,IFAC)
--      XH(1) = .5D0*X(1)
--      DO 105 I=3,N,2
--         XH(I-1) = -X(I)
--         XH(I) = XH(I-2)+X(I-1)
--  105 CONTINUE
--      IF (MODN .NE. 0) GO TO 106
--      XH(N) = -X(N+1)
--  106 DO 107 I=1,N
--      X(I) = WAR(I)
--      WAR(I) = XH(I)
--  107 CONTINUE
--      RETURN
--      END
--
--      SUBROUTINE DSINT (N,X,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       X(*)       ,WSAVE(*)
--      NP1 = N+1
--      IW1 = N/2+1
--      IW2 = IW1+NP1
--      IW3 = IW2+NP1
--      CALL DSINT1(N,X,WSAVE,WSAVE(IW1),WSAVE(IW2),WSAVE(IW3))
--      RETURN
--      END
--
--      SUBROUTINE DSINTI (N,WSAVE)
--	IMPLICIT DOUBLE PRECISION (A-H,O-Z)
--      DIMENSION       WSAVE(*)
--      DATA PI /3.1415926535897932384626433832795028D0/
--      IF (N .LE. 1) RETURN
--      NS2 = N/2
--      NP1 = N+1
--      DT = PI/DBLE(NP1)
--      DO 101 K=1,NS2
--         WSAVE(K) = 2.0D0*DSIN(K*DT)
--  101 CONTINUE
--      CALL DFFTI (NP1,WSAVE(NS2+1))
--      RETURN
--      END
-diff --git a/scipy/linalg/src/id_dist/src/id_rand.f b/scipy/linalg/src/id_dist/src/id_rand.f
-deleted file mode 100644
-index b49d2ef1f..000000000
---- a/scipy/linalg/src/id_dist/src/id_rand.f
-+++ /dev/null
-@@ -1,379 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine id_frand generates pseudorandom numbers
--c       drawn uniformly from [0,1]. id_frand is more
--c       efficient that id_srand, but cannot generate
--c       fewer than 55 pseudorandom numbers per call.
--c
--c       routine id_srand generates pseudorandom numbers
--c       drawn uniformly from [0,1]. id_srand is less
--c       efficient that id_frand, but can generate
--c       fewer than 55 pseudorandom numbers per call.
--c
--c       entry id_frandi initializes the seed values
--c       for routine id_frand.
--c
--c       entry id_srandi initializes the seed values
--c       for routine id_srand.
--c
--c       entry id_frando initializes the seed values
--c       for routine id_frand to their original values.
--c
--c       entry id_srando initializes the seed values
--c       for routine id_srand to their original values.
--c
--c       routine id_randperm generates a uniformly random permutation.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine id_frand(n,r)
--c
--c       generates n pseudorandom numbers drawn uniformly from [0,1],
--c       via a very efficient lagged Fibonnaci method.
--c       Unlike routine id_srand, the present routine requires that
--c       n be at least 55.
--c
--c       input:
--c       n -- number of pseudorandom numbers to generate
--c
--c       output:
--c       r -- array of pseudorandom numbers
--c
--c       _N.B._: n must be at least 55.
--c
--c       reference:
--c       Press, Teukolsky, Vetterling, Flannery, "Numerical Recipes,"
--c            3rd edition, Cambridge University Press, 2007,
--c            Section 7.1.5.
--c
--        implicit none
--        integer n,k
--        real*8 r(n),s(55),t(55),s0(55),x
--        save
--c
--        data s/
--     1  0.2793574644042651d0, 0.1882566493961346d0,
--     2  0.5202478134503912d0, 0.7568505373052146d0,
--     3  0.5682465992936152d0, 0.5153148754383294d0,
--     4  0.7806554095454596d0, 1.982474428974643d-2,
--     5  0.2520464262278498d0, 0.6423784715775962d0,
--     6  0.5802024387972178d0, 0.3784471040388249d0,
--     7  7.839919528229308d-2, 0.6334519212594525d0,
--     8  3.387627157788001d-2, 0.1709066283884670d0,
--     9  0.4801610983518325d0, 0.8983424668099422d0,
--     *  5.358948687598758d-2, 0.1265377231771848d0,
--     1  0.8979988627693677d0, 0.6470084038238917d0,
--     2  0.3031709395541237d0, 0.6674702804438126d0,
--     3  0.6318240977112699d0, 0.2235229633873050d0,
--     4  0.2784629939177633d0, 0.2365462014457445d0,
--     5  0.7226213454977284d0, 0.8986523045307989d0,
--     6  0.5488233229247885d0, 0.3924605412141200d0,
--     7  0.6288356378374988d0, 0.6370664115760445d0,
--     8  0.5925600062791174d0, 0.4322113919396362d0,
--     9  0.9766098520360393d0, 0.5168619893947437d0,
--     *  0.6799970440779681d0, 0.4196004604766881d0,
--     1  0.2324473089903044d0, 0.1439046416143282d0,
--     2  0.4670307948601256d0, 0.7076498261128343d0,
--     3  0.9458030397562582d0, 0.4557892460080424d0,
--     4  0.3905930854589403d0, 0.3361770064397268d0,
--     5  0.8303274937900278d0, 0.3041110304032945d0,
--     6  0.5752684022049654d0, 7.985703137991175d-2,
--     7  0.5522643936454465d0, 1.956754937251801d-2,
--     8  0.9920272858340107d0/
--c
--        data s0/
--     1  0.2793574644042651d0, 0.1882566493961346d0,
--     2  0.5202478134503912d0, 0.7568505373052146d0,
--     3  0.5682465992936152d0, 0.5153148754383294d0,
--     4  0.7806554095454596d0, 1.982474428974643d-2,
--     5  0.2520464262278498d0, 0.6423784715775962d0,
--     6  0.5802024387972178d0, 0.3784471040388249d0,
--     7  7.839919528229308d-2, 0.6334519212594525d0,
--     8  3.387627157788001d-2, 0.1709066283884670d0,
--     9  0.4801610983518325d0, 0.8983424668099422d0,
--     *  5.358948687598758d-2, 0.1265377231771848d0,
--     1  0.8979988627693677d0, 0.6470084038238917d0,
--     2  0.3031709395541237d0, 0.6674702804438126d0,
--     3  0.6318240977112699d0, 0.2235229633873050d0,
--     4  0.2784629939177633d0, 0.2365462014457445d0,
--     5  0.7226213454977284d0, 0.8986523045307989d0,
--     6  0.5488233229247885d0, 0.3924605412141200d0,
--     7  0.6288356378374988d0, 0.6370664115760445d0,
--     8  0.5925600062791174d0, 0.4322113919396362d0,
--     9  0.9766098520360393d0, 0.5168619893947437d0,
--     *  0.6799970440779681d0, 0.4196004604766881d0,
--     1  0.2324473089903044d0, 0.1439046416143282d0,
--     2  0.4670307948601256d0, 0.7076498261128343d0,
--     3  0.9458030397562582d0, 0.4557892460080424d0,
--     4  0.3905930854589403d0, 0.3361770064397268d0,
--     5  0.8303274937900278d0, 0.3041110304032945d0,
--     6  0.5752684022049654d0, 7.985703137991175d-2,
--     7  0.5522643936454465d0, 1.956754937251801d-2,
--     8  0.9920272858340107d0/
--c
--c
--        do k = 1,24
--c
--          x = s(k+31)-s(k)
--          if(x .lt. 0) x = x+1
--          r(k) = x
--c
--        enddo ! k
--c
--c
--        do k = 25,55
--c
--          x = r(k-24)-s(k)
--          if(x .lt. 0) x = x+1
--          r(k) = x
--c
--        enddo ! k
--c
--c
--        do k = 56,n
--c
--          x = r(k-24)-r(k-55)
--          if(x .lt. 0) x = x+1
--          r(k) = x
--c
--        enddo ! k
--c
--c
--        do k = 1,55
--          s(k) = r(n-55+k)
--        enddo ! k
--c
--c
--        return
--c
--c
--c
--        entry id_frandi(t)
--c
--c       initializes the seed values in s
--c       (any appropriately random numbers will do).
--c
--c       input:
--c       t -- values to copy into s
--c
--        do k = 1,55
--          s(k) = t(k)
--        enddo ! k
--c
--        return
--c
--c
--c
--        entry id_frando()
--c
--c       initializes the seed values in s to their original values.
--c
--        do k = 1,55
--          s(k) = s0(k)
--        enddo ! k
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine id_srand(n,r)
--c
--c       generates n pseudorandom numbers drawn uniformly from [0,1],
--c       via a very efficient lagged Fibonnaci method.
--c       Unlike routine id_frand, the present routine does not requires
--c       that n be at least 55.
--c
--c       input:
--c       n -- number of pseudorandom numbers to generate
--c
--c       output:
--c       r -- array of pseudorandom numbers
--c
--c       reference:
--c       Press, Teukolsky, Vetterling, Flannery, "Numerical Recipes,"
--c            3rd edition, Cambridge University Press, 2007,
--c            Section 7.1.5.
--c
--        implicit none
--        integer n,k,l,m
--        real*8 s(55),r(n),s0(55),t(55),x
--        save
--c
--        data l/55/,m/24/
--c
--        data s/
--     1  0.8966049453474352d0, 0.7789471911260157d0,
--     2  0.6071529762908476d0, 0.8287077988663865d0,
--     3  0.8249336255502409d0, 0.5735259423199479d0,
--     4  0.2436346323812991d0, 0.2656149927259701d0,
--     5  0.6594784809929011d0, 0.3432392503145575d0,
--     6  0.5051287353012308d0, 0.1444493249757482d0,
--     7  0.7643753221285416d0, 0.4843422506977382d0,
--     8  0.4427513254774826d0, 0.2965991475108561d0,
--     9  0.2650513544474467d0, 2.768759325778929d-2,
--     *  0.6106305243078063d0, 0.4246918885003141d0,
--     1  0.2863757386932874d0, 0.6211983878375777d0,
--     2  0.7534336463880467d0, 0.7471458603576737d0,
--     3  0.2017455446928328d0, 0.9334235874832779d0,
--     4  0.6343440435422822d0, 0.8819824804812527d0,
--     5  1.994761401222460d-2, 0.7023693520374801d0,
--     6  0.6010088924817263d0, 6.498095955562046d-2,
--     7  0.3090915456102685d0, 0.3014924769096677d0,
--     8  0.5820726822705102d0, 0.3630527222866207d0,
--     9  0.3787166916242271d0, 0.3932772088505305d0,
--     *  0.5570720335382000d0, 0.9712062146993835d0,
--     1  0.1338293907964648d0, 0.1857441593107195d0,
--     2  0.9102503893692572d0, 0.2623337538798778d0,
--     3  0.3542828591321135d0, 2.246286032456513d-2,
--     4  0.7935703170405717d0, 6.051464729640567d-2,
--     5  0.7271929955172147d0, 1.968513010678739d-3,
--     6  0.4914223624495486d0, 0.8730023176789450d0,
--     7  0.9639777091743168d0, 0.1084256187532446d0,
--     8  0.8539399636754000d0/
--c
--        data s0/
--     1  0.8966049453474352d0, 0.7789471911260157d0,
--     2  0.6071529762908476d0, 0.8287077988663865d0,
--     3  0.8249336255502409d0, 0.5735259423199479d0,
--     4  0.2436346323812991d0, 0.2656149927259701d0,
--     5  0.6594784809929011d0, 0.3432392503145575d0,
--     6  0.5051287353012308d0, 0.1444493249757482d0,
--     7  0.7643753221285416d0, 0.4843422506977382d0,
--     8  0.4427513254774826d0, 0.2965991475108561d0,
--     9  0.2650513544474467d0, 2.768759325778929d-2,
--     *  0.6106305243078063d0, 0.4246918885003141d0,
--     1  0.2863757386932874d0, 0.6211983878375777d0,
--     2  0.7534336463880467d0, 0.7471458603576737d0,
--     3  0.2017455446928328d0, 0.9334235874832779d0,
--     4  0.6343440435422822d0, 0.8819824804812527d0,
--     5  1.994761401222460d-2, 0.7023693520374801d0,
--     6  0.6010088924817263d0, 6.498095955562046d-2,
--     7  0.3090915456102685d0, 0.3014924769096677d0,
--     8  0.5820726822705102d0, 0.3630527222866207d0,
--     9  0.3787166916242271d0, 0.3932772088505305d0,
--     *  0.5570720335382000d0, 0.9712062146993835d0,
--     1  0.1338293907964648d0, 0.1857441593107195d0,
--     2  0.9102503893692572d0, 0.2623337538798778d0,
--     3  0.3542828591321135d0, 2.246286032456513d-2,
--     4  0.7935703170405717d0, 6.051464729640567d-2,
--     5  0.7271929955172147d0, 1.968513010678739d-3,
--     6  0.4914223624495486d0, 0.8730023176789450d0,
--     7  0.9639777091743168d0, 0.1084256187532446d0,
--     8  0.8539399636754000d0/
--c
--c
--        do k = 1,n
--c
--c         Run one step of the recurrence.
--c
--          x = s(m)-s(l)
--          if(x .lt. 0) x = x+1
--          s(l) = x
--          r(k) = x
--c
--c         Decrement l and m.
--c
--          l = l-1
--          m = m-1
--c
--c         Circle back to the end if required.
--c
--          if(l .eq. 0) l = 55
--          if(m .eq. 0) m = 55
--c
--        enddo ! k
--c
--c
--        return
--c
--c
--c
--        entry id_srandi(t)
--c
--c       initializes the seed values in s
--c       (any appropriately random numbers will do).
--c
--c       input:
--c       t -- values to copy into s
--c
--        do k = 1,55
--          s(k) = t(k)
--        enddo ! k
--c
--        l = 55
--        m = 24
--c
--        return
--c
--c
--c
--        entry id_srando()
--c
--c       initializes the seed values in s to their original values.
--c
--        do k = 1,55
--          s(k) = s0(k)
--        enddo ! k
--c
--        l = 55
--        m = 24
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine id_randperm(n,ind)
--c
--c       draws a permutation ind uniformly at random from the group
--c       of all permutations of n objects.
--c
--c       input:
--c       n -- length of ind
--c
--c       output:
--c       ind -- random permutation of length n
--c
--        implicit none
--        integer n,ind(n),m,j,iswap
--        real*8 r
--c
--c
--c       Initialize ind.
--c
--        do j = 1,n
--          ind(j) = j
--        enddo ! j
--c
--c
--c       Shuffle ind via the Fisher-Yates (Knuth/Durstenfeld) algorithm.
--c
--        do m = n,2,-1
--c
--c         Draw an integer uniformly at random from 1, 2, ..., m.
--c
--          call id_srand(1,r)
--          j = m*r+1
--c
--c         Uncomment the following line if r could equal 1:
--c         if(j .eq. m+1) j = m
--c
--c         Swap ind(j) and ind(m).
--c
--          iswap = ind(j)
--          ind(j) = ind(m)
--          ind(m) = iswap
--c
--        enddo ! m
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/id_rtrans.f b/scipy/linalg/src/id_dist/src/id_rtrans.f
-deleted file mode 100644
-index a970d7fb5..000000000
---- a/scipy/linalg/src/id_dist/src/id_rtrans.f
-+++ /dev/null
-@@ -1,746 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idd_random_transf applies rapidly
--c       a random orthogonal matrix to a user-supplied vector.
--c
--c       routine idd_random_transf_inverse applies rapidly
--c       the inverse of the operator applied
--c       by routine idd_random_transf.
--c
--c       routine idz_random_transf applies rapidly
--c       a random unitary matrix to a user-supplied vector.
--c
--c       routine idz_random_transf_inverse applies rapidly
--c       the inverse of the operator applied
--c       by routine idz_random_transf.
--c
--c       routine idd_random_transf_init initializes data
--c       for routines idd_random_transf and idd_random_transf_inverse.
--c
--c       routine idz_random_transf_init initializes data
--c       for routines idz_random_transf and idz_random_transf_inverse.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--c
--        subroutine idd_random_transf_init(nsteps,n,w,keep)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension w(*)
--c
--c       prepares and stores in array w the data used
--c       by the routines idd_random_transf and idd_random_transf_inverse
--c       to apply rapidly a random orthogonal matrix
--c       to an arbitrary user-specified vector.
--c
--c       input:
--c       nsteps -- the degree of randomness of the operator
--c                 to be applied
--c       n -- the size of the matrix to be applied
--c
--c       output:
--c       w -- the first keep elements of w contain all the data
--c            to be used by routines idd_random_tranf
--c            and idd_random_transf_inverse. Please note that
--c            the number of elements used by the present routine
--c            is also equal to keep. This array should be at least
--c            3*nsteps*n + 2*n + n/4 + 50 real*8 elements long.
--c       keep - the number of elements in w actually used
--c              by the present routine; keep is also the number
--c              of elements that must not be changed between the call
--c              to this routine and subsequent calls to routines
--c              idd_random_transf and idd_random_transf_inverse.
--c
--c
--c        . . . allocate memory
--c
--        ninire=2
--c
--        ialbetas=10
--        lalbetas=2*n*nsteps+10
--c
--        iixs=ialbetas+lalbetas
--        lixs=n*nsteps/ninire+10
--c
--        iww=iixs+lixs
--        lww=2*n+n/4+20
--c
--        keep=iww+lww
--c
--        w(1)=ialbetas+0.1
--        w(2)=iixs+0.1
--        w(3)=nsteps+0.1
--        w(4)=iww+0.1
--        w(5)=n+0.1
--c
--        call idd_random_transf_init0(nsteps,n,w(ialbetas),w(iixs))
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idz_random_transf_init(nsteps,n,w,keep)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension w(*)
--c
--c       prepares and stores in array w the data used
--c       by routines idz_random_transf and idz_random_transf_inverse
--c       to apply rapidly a random unitary matrix
--c       to an arbitrary user-specified vector.
--c
--c       input:
--c       nsteps -- the degree of randomness of the operator
--c                 to be applied
--c       n -- the size of the matrix to be applied
--c
--c       output:
--c       w -- the first keep elements of w contain all the data
--c            to be used by routines idz_random_transf
--c            and idz_random_transf_inverse. Please note that
--c            the number of elements used by the present routine
--c            is also equal to keep. This array should be at least
--c            5*nsteps*n + 2*n + n/4 + 60 real*8 elements long.
--c       keep - the number of elements in w actually used
--c              by the present routine; keep is also the number
--c              of elements that must not be changed between the call
--c              to this routine and subsequent calls to routines
--c              idz_random_transf and idz_random_transf_inverse.
--c
--c
--c        . . . allocate memory
--c
--        ninire=2
--c
--        ialbetas=10
--        lalbetas=2*n*nsteps+10
--c
--        igammas=ialbetas+lalbetas
--        lgammas=2*n*nsteps+10
--c
--        iixs=igammas+lgammas
--        lixs=n*nsteps/ninire+10
--c
--        iww=iixs+lixs
--        lww=2*n+n/4+20
--c
--        keep=iww+lww
--c
--        w(1)=ialbetas+0.1
--        w(2)=iixs+0.1
--        w(3)=nsteps+0.1
--        w(4)=iww+0.1
--        w(5)=n+0.1
--        w(6)=igammas+0.1
--c
--        call idz_random_transf_init0(nsteps,n,w(ialbetas),
--     1      w(igammas),w(iixs))
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idd_random_transf(x,y,w)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension x(*),y(*),w(*)
--c
--c       applies rapidly a random orthogonal matrix
--c       to the user-specified real vector x,
--c       using the data in array w stored there by a preceding
--c       call to routine idd_random_transf_init.
--c
--c       input:
--c       x -- the vector of length n to which the random matrix is
--c            to be applied
--c       w -- array containing all initialization data
--c
--c       output:
--c       y -- the result of applying the random matrix to x
--c
--c
--c        . . . allocate memory
--c
--        ialbetas=w(1)
--        iixs=w(2)
--        nsteps=w(3)
--        iww=w(4)
--        n=w(5)
--c
--        call idd_random_transf0(nsteps,x,y,n,w(iww),
--     1      w(ialbetas),w(iixs))
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idd_random_transf_inverse(x,y,w)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension x(*),y(*),w(*)
--c
--c       applies rapidly a random orthogonal matrix
--c       to the user-specified real vector x,
--c       using the data in array w stored there by a preceding
--c       call to routine idd_random_transf_init.
--c       The transformation applied by the present routine is
--c       the inverse of the transformation applied
--c       by routine idd_random_transf.
--c
--c       input:
--c       x -- the vector of length n to which the random matrix is
--c            to be applied
--c       w -- array containing all initialization data
--c
--c       output:
--c       y -- the result of applying the random matrix to x
--c
--c
--c        . . . allocate memory
--c
--        ialbetas=w(1)
--        iixs=w(2)
--        nsteps=w(3)
--        iww=w(4)
--        n=w(5)
--c
--        call idd_random_transf0_inv(nsteps,x,y,n,w(iww),
--     1      w(ialbetas),w(iixs))
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idz_random_transf(x,y,w)
--        implicit real *8 (a-h,o-z)
--        save
--        complex *16 x(*),y(*)
--        dimension w(*)
--c
--c       applies rapidly a random unitary matrix
--c       to the user-specified vector x,
--c       using the data in array w stored there by a preceding
--c       call to routine idz_random_transf_init.
--c
--c       input:
--c       x -- the vector of length n to which the random matrix is
--c            to be applied
--c       w -- array containing all initialization data
--c
--c       output:
--c       y -- the result of applying the random matrix to x
--c
--c
--c        . . . allocate memory
--c
--        ialbetas=w(1)
--        iixs=w(2)
--        nsteps=w(3)
--        iww=w(4)
--        n=w(5)
--        igammas=w(6)
--c
--        call idz_random_transf0(nsteps,x,y,n,w(iww),w(ialbetas),
--     1      w(igammas),w(iixs))
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idz_random_transf_inverse(x,y,w)
--        implicit real *8 (a-h,o-z)
--        save
--        complex *16 x(*),y(*)
--        dimension w(*)
--c
--c       applies rapidly a random unitary matrix
--c       to the user-specified vector x,
--c       using the data in array w stored there by a preceding
--c       call to routine idz_random_transf_init.
--c       The transformation applied by the present routine is
--c       the inverse of the transformation applied
--c       by routine idz_random_transf.
--c
--c       input:
--c       x -- the vector of length n to which the random matrix is
--c            to be applied
--c       w -- array containing all initialization data
--c
--c       output:
--c       y -- the result of applying the random matrix to x
--c
--c
--c        . . . allocate memory
--c
--        ialbetas=w(1)
--        iixs=w(2)
--        nsteps=w(3)
--        iww=w(4)
--        n=w(5)
--        igammas=w(6)
--c
--        call idz_random_transf0_inv(nsteps,x,y,n,w(iww),
--     1      w(ialbetas),w(igammas),w(iixs))
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idd_random_transf0_inv(nsteps,x,y,n,w2,albetas,iixs)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension x(*),y(*),w2(*),albetas(2,n,*),iixs(n,*)
--c
--c       routine idd_random_transf_inverse serves as a memory wrapper
--c       for the present routine; see routine idd_random_transf_inverse
--c       for documentation.
--c
--        do 1200 i=1,n
--c
--        w2(i)=x(i)
-- 1200 continue
--c
--        do 2000 ijk=nsteps,1,-1
--c
--        call idd_random_transf00_inv(w2,y,n,albetas(1,1,ijk),
--     1      iixs(1,ijk) )
--c
--        do 1400 j=1,n
--c
--        w2(j)=y(j)
-- 1400 continue
-- 2000 continue
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idd_random_transf00_inv(x,y,n,albetas,ixs)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension x(*),y(*),albetas(2,*),ixs(*)
--c
--c       implements one step of the random transform required
--c       by routine idd_random_transf0_inv (please see the latter).
--c
--c
--c        implement 2 \times 2 matrices
--c
--        do 1600 i=1,n
--        y(i)=x(i)
-- 1600 continue
--c
--        do 1800 i=n-1,1,-1
--c
--        alpha=albetas(1,i)
--        beta=albetas(2,i)
--c
--        a=y(i)
--        b=y(i+1)
--c
--        y(i)=alpha*a-beta*b
--        y(i+1)=beta*a+alpha*b
-- 1800 continue
--c
--c        implement the permutation
--c
--        do 2600 i=1,n
--c
--        j=ixs(i)
--        x(j)=y(i)
-- 2600 continue
--c
--        do 2800 i=1,n
--c
--        y(i)=x(i)
-- 2800 continue
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idz_random_transf0_inv(nsteps,x,y,n,w2,albetas,
--     1      gammas,iixs)
--        implicit real *8 (a-h,o-z)
--        save
--        complex *16 x(*),y(*),w2(*),gammas(n,*)
--        dimension albetas(2,n,*),iixs(n,*)
--c
--c       routine idz_random_transf_inverse serves as a memory wrapper
--c       for the present routine; please see routine
--c       idz_random_transf_inverse for documentation.
--c
--        do 1200 i=1,n
--c
--        w2(i)=x(i)
-- 1200 continue
--c
--        do 2000 ijk=nsteps,1,-1
--c
--        call idz_random_transf00_inv(w2,y,n,albetas(1,1,ijk),
--     1      gammas(1,ijk),iixs(1,ijk) )
--c
--        do 1400 j=1,n
--c
--        w2(j)=y(j)
-- 1400 continue
-- 2000 continue
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idz_random_transf00_inv(x,y,n,albetas,gammas,ixs)
--        implicit real *8 (a-h,o-z)
--        save
--        complex *16 x(*),y(*),gammas(*),a,b
--        dimension albetas(2,*),ixs(*)
--c
--c       implements one step of the random transform
--c       required by routine idz_random_transf0_inv
--c       (please see the latter).
--c
--c        implement 2 \times 2 matrices
--c
--        do 1600 i=n-1,1,-1
--c
--        alpha=albetas(1,i)
--        beta=albetas(2,i)
--c
--        a=x(i)
--        b=x(i+1)
--c
--        x(i)=alpha*a-beta*b
--        x(i+1)=beta*a+alpha*b
-- 1600 continue
--c
--c        implement the permutation
--c        and divide by the random numbers on the unit circle
--c        (or, equivalently, multiply by their conjugates)
--c
--        do 1800 i=1,n
--c
--        j=ixs(i)
--        y(j)=x(i)*conjg(gammas(i))
-- 1800 continue
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idd_random_transf0(nsteps,x,y,n,w2,albetas,iixs)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension x(*),y(*),w2(*),albetas(2,n,*),iixs(n,*)
--c
--c       routine idd_random_transf serves as a memory wrapper
--c       for the present routine; please see routine idd_random_transf
--c       for documentation.
--c
--        do 1200 i=1,n
--c
--        w2(i)=x(i)
-- 1200 continue
--c
--        do 2000 ijk=1,nsteps
--c
--        call idd_random_transf00(w2,y,n,albetas(1,1,ijk),iixs(1,ijk) )
--c
--        do 1400 j=1,n
--c
--        w2(j)=y(j)
-- 1400 continue
-- 2000 continue
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idd_random_transf00(x,y,n,albetas,ixs)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension x(*),y(*),albetas(2,*),ixs(*)
--c
--c       implements one step of the random transform
--c       required by routine idd_random_transf0 (please see the latter).
--c
--c        implement the permutation
--c
--        do 1600 i=1,n
--c
--        j=ixs(i)
--        y(i)=x(j)
-- 1600 continue
--c
--c        implement 2 \times 2 matrices
--c
--        do 1800 i=1,n-1
--c
--        alpha=albetas(1,i)
--        beta=albetas(2,i)
--c
--        a=y(i)
--        b=y(i+1)
--c
--        y(i)=alpha*a+beta*b
--        y(i+1)=-beta*a+alpha*b
-- 1800 continue
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idz_random_transf_init0(nsteps,n,albetas,gammas,ixs)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension albetas(2,n,*),ixs(n,*)
--        complex *16 gammas(n,*)
--c
--c       routine idz_random_transf_init serves as a memory wrapper
--c       for the present routine; please see routine
--c       idz_random_transf_init for documentation.
--c
--        do 2000 ijk=1,nsteps
--c
--        call idz_random_transf_init00(n,albetas(1,1,ijk),
--     1      gammas(1,ijk),ixs(1,ijk) )
-- 2000 continue
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idz_random_transf_init00(n,albetas,gammas,ixs)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension albetas(2,*),gammas(*),ixs(*)
--c
--c       constructs one stage of the random transform
--c       initialized by routine idz_random_transf_init0
--c       (please see the latter).
--c
--        done=1
--        twopi=2*4*atan(done)
--c
--c        construct the random permutation
--c
--        ifrepeat=0
--        call id_randperm(n,ixs)
--c
--c        construct the random variables
--c
--        call id_srand(2*n,albetas)
--        call id_srand(2*n,gammas)
--c
--        do 1300 i=1,n
--c
--        albetas(1,i)=2*albetas(1,i)-1
--        albetas(2,i)=2*albetas(2,i)-1
--        gammas(2*i-1)=2*gammas(2*i-1)-1
--        gammas(2*i)=2*gammas(2*i)-1
-- 1300 continue
--c
--c        construct the random 2 \times 2 transformations
--c
--        do 1400 i=1,n
--c
--        d=albetas(1,i)**2+albetas(2,i)**2
--        d=1/sqrt(d)
--        albetas(1,i)=albetas(1,i)*d
--        albetas(2,i)=albetas(2,i)*d
-- 1400 continue
--c
--c        construct the random multipliers on the unit circle
--c
--        do 1500 i=1,n
--c
--        d=gammas(2*i-1)**2+gammas(2*i)**2
--        d=1/sqrt(d)
--c
--c        fill the real part
--c
--        gammas(2*i-1)=gammas(2*i-1)*d
--c
--c        fill the imaginary part
--c
--        gammas(2*i)=gammas(2*i)*d
-- 1500 continue
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idz_random_transf0(nsteps,x,y,n,w2,albetas,
--     1      gammas,iixs)
--        implicit real *8 (a-h,o-z)
--        save
--        complex *16 x(*),y(*),w2(*),gammas(n,*)
--        dimension albetas(2,n,*),iixs(n,*)
--c
--c       routine idz_random_transf serves as a memory wrapper
--c       for the present routine; please see routine idz_random_transf
--c       for documentation.
--c
--        do 1200 i=1,n
--c
--        w2(i)=x(i)
-- 1200 continue
--c
--        do 2000 ijk=1,nsteps
--c
--        call idz_random_transf00(w2,y,n,albetas(1,1,ijk),
--     1      gammas(1,ijk),iixs(1,ijk) )
--        do 1400 j=1,n
--c
--        w2(j)=y(j)
-- 1400 continue
-- 2000 continue
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idz_random_transf00(x,y,n,albetas,gammas,ixs)
--        implicit real *8 (a-h,o-z)
--        save
--        complex *16 x(*),y(*),gammas(*),a,b
--        dimension albetas(2,*),ixs(*)
--c
--c       implements one step of the random transform
--c       required by routine idz_random_transf0 (please see the latter).
--c
--c        implement the permutation
--c        and multiply by the random numbers
--c        on the unit circle
--c
--        do 1600 i=1,n
--c
--        j=ixs(i)
--        y(i)=x(j)*gammas(i)
-- 1600 continue
--c
--c        implement 2 \times 2 matrices
--c
--        do 2600 i=1,n-1
--c
--        alpha=albetas(1,i)
--        beta=albetas(2,i)
--c
--        a=y(i)
--        b=y(i+1)
--c
--        y(i)=alpha*a+beta*b
--        y(i+1)=-beta*a+alpha*b
-- 2600 continue
--c
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idd_random_transf_init0(nsteps,n,albetas,ixs)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension albetas(2,n,*),ixs(n,*)
--c
--c       routine idd_random_transf_init serves as a memory wrapper
--c       for the present routine; please see routine
--c       idd_random_transf_init for documentation.
--c
--        do 2000 ijk=1,nsteps
--c
--        call idd_random_transf_init00(n,albetas(1,1,ijk),ixs(1,ijk) )
-- 2000 continue
--        return
--        end
--c
--c
--c
--c
--c
--        subroutine idd_random_transf_init00(n,albetas,ixs)
--        implicit real *8 (a-h,o-z)
--        save
--        dimension albetas(2,*),ixs(*)
--c
--c       constructs one stage of the random transform
--c       initialized by routine idd_random_transf_init0
--c       (please see the latter).
--c
--c        construct the random permutation
--c
--        ifrepeat=0
--        call id_randperm(n,ixs)
--c
--c        construct the random variables
--c
--        call id_srand(2*n,albetas)
--c
--        do 1300 i=1,n
--c
--        albetas(1,i)=2*albetas(1,i)-1
--        albetas(2,i)=2*albetas(2,i)-1
-- 1300 continue
--c
--c        construct the random 2 \times 2 transformations
--c
--        do 1400 i=1,n
--c
--        d=albetas(1,i)**2+albetas(2,i)**2
--        d=1/sqrt(d)
--        albetas(1,i)=albetas(1,i)*d
--        albetas(2,i)=albetas(2,i)*d
-- 1400 continue
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idd_frm.f b/scipy/linalg/src/id_dist/src/idd_frm.f
-deleted file mode 100644
-index 0a13112eb..000000000
---- a/scipy/linalg/src/id_dist/src/idd_frm.f
-+++ /dev/null
-@@ -1,525 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idd_frm transforms a vector via a composition
--c       of Rokhlin's random transform, random subselection, and an FFT.
--c
--c       routine idd_sfrm transforms a vector into a vector
--c       of specified length via a composition
--c       of Rokhlin's random transform, random subselection, and an FFT.
--c
--c       routine idd_frmi initializes routine idd_frm.
--c
--c       routine idd_sfrmi initializes routine idd_sfrm.
--c
--c       routine idd_pairsamps calculates the indices of the pairs
--c       of integers to which the individual integers
--c       in a specified set belong.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idd_frm(m,n,w,x,y)
--c
--c       transforms x into y via a composition
--c       of Rokhlin's random transform, random subselection, and an FFT.
--c       In contrast to routine idd_sfrm, the present routine works best
--c       when the length of the transformed vector is the integer n
--c       output by routine idd_frmi, or when the length
--c       is not specified, but instead determined a posteriori
--c       using the output of the present routine. The transformed vector
--c       output by the present routine is randomly permuted.
--c
--c       input:
--c       m -- length of x
--c       n -- greatest integer expressible as a positive integer power
--c            of 2 that is less than or equal to m, as obtained
--c            from the routine idd_frmi; n is the length of y
--c       w -- initialization array constructed by routine idd_frmi
--c       x -- vector to be transformed
--c
--c       output:
--c       y -- transform of x
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,iw,n,k
--        real*8 w(17*m+70),x(m),y(n)
--c
--c
--c       Apply Rokhlin's random transformation to x, obtaining
--c       w(16*m+71 : 17*m+70).
--c
--        iw = w(3+m+n)
--        call idd_random_transf(x,w(16*m+70+1),w(iw))
--c
--c
--c       Subselect from  w(16*m+71 : 17*m+70)  to obtain y.
--c
--        call idd_subselect(n,w(3),m,w(16*m+70+1),y)
--c
--c
--c       Copy y into  w(16*m+71 : 16*m+n+70).
--c
--        do k = 1,n
--          w(16*m+70+k) = y(k)
--        enddo ! k
--c
--c
--c       Fourier transform  w(16*m+71 : 16*m+n+70).
--c
--        call dfftf(n,w(16*m+70+1),w(4+m+n))
--c
--c
--c       Permute  w(16*m+71 : 16*m+n+70)  to obtain y.
--c
--        call idd_permute(n,w(3+m),w(16*m+70+1),y)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_sfrm(l,m,n,w,x,y)
--c
--c       transforms x into y via a composition
--c       of Rokhlin's random transform, random subselection, and an FFT.
--c       In contrast to routine idd_frm, the present routine works best
--c       when the length l of the transformed vector is known a priori.
--c
--c       input:
--c       l -- length of y; l must be less than or equal to n
--c       m -- length of x
--c       n -- greatest integer expressible as a positive integer power
--c            of 2 that is less than or equal to m, as obtained
--c            from the routine idd_sfrmi
--c       w -- initialization array constructed by routine idd_sfrmi
--c       x -- vector to be transformed
--c
--c       output:
--c       y -- transform of x
--c
--c       _N.B._: l must be less than or equal to n.
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,iw,n,l,l2
--        real*8 w(27*m+90),x(m),y(l)
--c
--c
--c       Retrieve the number of pairs of outputs to be calculated
--c       via sfft.
--c
--        l2 = w(3)
--c
--c
--c       Apply Rokhlin's random transformation to x, obtaining
--c       w(25*m+91 : 26*m+90).
--c
--        iw = w(4+m+l+l2)
--        call idd_random_transf(x,w(25*m+90+1),w(iw))
--c
--c
--c       Subselect from  w(25*m+91 : 26*m+90)  to obtain
--c       w(26*m+91 : 26*m+n+90).
--c
--        call idd_subselect(n,w(4),m,w(25*m+90+1),w(26*m+90+1))
--c
--c
--c       Fourier transform  w(26*m+91 : 26*m+n+90).
--c
--        call idd_sfft(l2,w(4+m+l),n,w(5+m+l+l2),w(26*m+90+1))
--c
--c
--c       Copy the desired entries from  w(26*m+91 : 26*m+n+90)
--c       to y.
--c
--        call idd_subselect(l,w(4+m),n,w(26*m+90+1),y)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_pairsamps(n,l,ind,l2,ind2,marker)
--c
--c       calculates the indices of the l2 pairs of integers
--c       to which the l individual integers from ind belong.
--c       The integers in ind may range from 1 to n.
--c
--c       input:
--c       n -- upper bound on the integers in ind
--c            (the number 1 must be a lower bound);
--c            n must be even
--c       l -- length of ind
--c       ind -- integers selected from 1 to n
--c
--c       output:
--c       l2 -- length of ind2
--c       ind2 -- indices in the range from 1 to n/2 of the pairs
--c               of integers to which the entries of ind belong
--c
--c       work:
--c       marker -- must be at least n/2 integer elements long
--c
--c       _N.B._: n must be even.
--c
--        implicit none
--        integer l,n,ind(l),ind2(l),marker(n/2),l2,k
--c
--c
--c       Unmark all pairs.
--c
--        do k = 1,n/2
--          marker(k) = 0
--        enddo ! k
--c
--c
--c       Mark the required pairs.
--c
--        do k = 1,l
--          marker((ind(k)+1)/2) = marker((ind(k)+1)/2)+1
--        enddo ! k
--c
--c
--c       Record the required pairs in indpair.
--c
--        l2 = 0
--c
--        do k = 1,n/2
--c
--          if(marker(k) .ne. 0) then
--            l2 = l2+1
--            ind2(l2) = k
--          endif
--c
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_permute(n,ind,x,y)
--c
--c       copy the entries of x into y, rearranged according
--c       to the permutation specified by ind.
--c
--c       input:
--c       n -- length of ind, x, and y
--c       ind -- permutation of n objects
--c       x -- vector to be permuted
--c
--c       output:
--c       y -- permutation of x
--c
--        implicit none
--        integer n,ind(n),k
--        real*8 x(n),y(n)
--c
--c
--        do k = 1,n
--          y(k) = x(ind(k))
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_subselect(n,ind,m,x,y)
--c
--c       copies into y the entries of x indicated by ind.
--c
--c       input:
--c       n -- number of entries of x to copy into y
--c       ind -- indices of the entries in x to copy into y
--c       m -- length of x
--c       x -- vector whose entries are to be copied
--c
--c       output:
--c       y -- collection of entries of x specified by ind
--c
--        implicit none
--        integer n,ind(n),m,k
--        real*8 x(m),y(n)
--c
--c
--        do k = 1,n
--          y(k) = x(ind(k))
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_frmi(m,n,w)
--c
--c       initializes data for the routine idd_frm.
--c
--c       input:
--c       m -- length of the vector to be transformed
--c
--c       output:
--c       n -- greatest integer expressible as a positive integer power
--c            of 2 that is less than or equal to m
--c       w -- initialization array to be used by routine idd_frm
--c
--c
--c       glossary for the fully initialized w:
--c
--c       w(1) = m
--c       w(2) = n
--c       w(3:2+m) stores a permutation of m objects
--c       w(3+m:2+m+n) stores a permutation of n objects
--c       w(3+m+n) = address in w of the initialization array
--c                  for idd_random_transf
--c       w(4+m+n:int(w(3+m+n))-1) stores the initialization array
--c                                for dfft
--c       w(int(w(3+m+n)):16*m+70) stores the initialization array
--c                                for idd_random_transf
--c
--c
--c       _N.B._: n is an output of the present routine;
--c               this routine changes n.
--c
--c
--        implicit none
--        integer m,n,l,nsteps,keep,lw,ia
--        real*8 w(17*m+70)
--c
--c
--c       Find the greatest integer less than or equal to m
--c       which is a power of two.
--c
--        call idd_poweroftwo(m,l,n)
--c
--c
--c       Store m and n in w.
--c
--        w(1) = m
--        w(2) = n
--c
--c
--c       Store random permutations of m and n objects in w.
--c
--        call id_randperm(m,w(3))
--        call id_randperm(n,w(3+m))
--c
--c
--c       Store the address within w of the idd_random_transf_init
--c       initialization data.
--c
--        ia = 4+m+n+2*n+15
--        w(3+m+n) = ia
--c
--c
--c       Store the initialization data for dfft in w.
--c
--        call dffti(n,w(4+m+n))
--c
--c
--c       Store the initialization data for idd_random_transf_init in w.
--c
--        nsteps = 3
--        call idd_random_transf_init(nsteps,m,w(ia),keep)
--c
--c
--c       Calculate the total number of elements used in w.
--c
--        lw = 3+m+n+2*n+15 + 3*nsteps*m+2*m+m/4+50
--c
--        if(16*m+70 .lt. lw) then
--          call prinf('lw = *',lw,1)
--          call prinf('16m+70 = *',16*m+70,1)
--          stop
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_sfrmi(l,m,n,w)
--c
--c       initializes data for the routine idd_sfrm.
--c
--c       input:
--c       l -- length of the transformed (output) vector
--c       m -- length of the vector to be transformed
--c
--c       output:
--c       n -- greatest integer expressible as a positive integer power
--c            of 2 that is less than or equal to m
--c       w -- initialization array to be used by routine idd_sfrm
--c
--c
--c       glossary for the fully initialized w:
--c
--c       w(1) = m
--c       w(2) = n
--c       w(3) = l2
--c       w(4:3+m) stores a permutation of m objects
--c       w(4+m:3+m+l) stores the indices of the l outputs which idd_sfft
--c                    calculates
--c       w(4+m+l:3+m+l+l2) stores the indices of the l2 pairs of outputs
--c                         which idd_sfft calculates
--c       w(4+m+l+l2) = address in w of the initialization array
--c                     for idd_random_transf
--c       w(5+m+l+l2:int(w(4+m+l+l2))-1) stores the initialization array
--c                                      for idd_sfft
--c       w(int(w(4+m+l+l2)):25*m+90) stores the initialization array
--c                                   for idd_random_transf
--c
--c
--c       _N.B._: n is an output of the present routine;
--c               this routine changes n.
--c
--c
--        implicit none
--        integer l,m,n,idummy,nsteps,keep,lw,l2,ia
--        real*8 w(27*m+90)
--c
--c
--c       Find the greatest integer less than or equal to m
--c       which is a power of two.
--c
--        call idd_poweroftwo(m,idummy,n)
--c
--c
--c       Store m and n in w.
--c
--        w(1) = m
--        w(2) = n
--c
--c
--c       Store random permutations of m and n objects in w.
--c
--        call id_randperm(m,w(4))
--        call id_randperm(n,w(4+m))
--c
--c
--c       Find the pairs of integers covering the integers in
--c       w(4+m : 3+m+(l+1)/2).
--c
--        call idd_pairsamps(n,l,w(4+m),l2,w(4+m+2*l),w(4+m+3*l))
--        w(3) = l2
--        call idd_copyints(l2,w(4+m+2*l),w(4+m+l))
--c
--c
--c       Store the address within w of the idd_random_transf_init
--c       initialization data.
--c
--        ia = 5+m+l+l2+4*l2+30+8*n
--        w(4+m+l+l2) = ia
--c
--c
--c       Store the initialization data for idd_sfft in w.
--c
--        call idd_sffti(l2,w(4+m+l),n,w(5+m+l+l2))
--c
--c
--c       Store the initialization data for idd_random_transf_init in w.
--c
--        nsteps = 3
--        call idd_random_transf_init(nsteps,m,w(ia),keep)
--c
--c
--c       Calculate the total number of elements used in w.
--c
--        lw = 4+m+l+l2+4*l2+30+8*n + 3*nsteps*m+2*m+m/4+50
--c
--        if(25*m+90 .lt. lw) then
--          call prinf('lw = *',lw,1)
--          call prinf('25m+90 = *',25*m+90,1)
--          stop
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_copyints(n,ia,ib)
--c
--c       copies ia into ib.
--c
--c       input:
--c       n -- length of ia and ib
--c       ia -- array to be copied
--c
--c       output:
--c       ib -- copy of ia
--c
--        implicit none
--        integer n,ia(n),ib(n),k
--c
--c
--        do k = 1,n
--          ib(k) = ia(k)
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_poweroftwo(m,l,n)
--c
--c       computes l = floor(log_2(m)) and n = 2**l.
--c
--c       input:
--c       m -- integer whose log_2 is to be taken
--c
--c       output:
--c       l -- floor(log_2(m))
--c       n -- 2**l
--c
--        implicit none
--        integer l,m,n
--c
--c
--        l = 0
--        n = 1
--c
-- 1000   continue
--          l = l+1
--          n = n*2
--        if(n .le. m) goto 1000
--c
--        l = l-1
--        n = n/2
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idd_house.f b/scipy/linalg/src/id_dist/src/idd_house.f
-deleted file mode 100644
-index 715037117..000000000
---- a/scipy/linalg/src/id_dist/src/idd_house.f
-+++ /dev/null
-@@ -1,288 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idd_house calculates the vector and scalar
--c       needed to apply the Householder transformation reflecting
--c       a given vector into its first component.
--c
--c       routine idd_houseapp applies a Householder matrix to a vector.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idd_houseapp(n,vn,u,ifrescal,scal,v)
--c
--c       applies the Householder matrix
--c       identity_matrix - scal * vn * transpose(vn)
--c       to the vector u, yielding the vector v;
--c
--c       scal = 2/(1 + vn(2)^2 + ... + vn(n)^2)
--c       when vn(2), ..., vn(n) don't all vanish;
--c
--c       scal = 0
--c       when vn(2), ..., vn(n) do all vanish
--c       (including when n = 1).
--c
--c       input:
--c       n -- size of vn, u, and v, though the indexing on vn goes
--c            from 2 to n
--c       vn -- components 2 to n of the Householder vector vn;
--c             vn(1) is assumed to be 1
--c       u -- vector to be transformed
--c       ifrescal -- set to 1 to recompute scal from vn(2), ..., vn(n);
--c                   set to 0 to use scal as input
--c       scal -- see the entry for ifrescal in the decription
--c               of the input
--c
--c       output:
--c       scal -- see the entry for ifrescal in the decription
--c               of the input
--c       v -- result of applying the Householder matrix to u;
--c            it's O.K. to have v be the same as u
--c            in order to apply the matrix to the vector in place
--c
--c       reference:
--c       Golub and Van Loan, "Matrix Computations," 3rd edition,
--c            Johns Hopkins University Press, 1996, Chapter 5.
--c
--        implicit none
--        save
--        integer n,k,ifrescal
--        real*8 vn(2:*),scal,u(n),v(n),fact,sum
--c
--c
--c       Get out of this routine if n = 1.
--c
--        if(n .eq. 1) then
--          v(1) = u(1)
--          return
--        endif
--c
--c
--        if(ifrescal .eq. 1) then
--c
--c
--c         Calculate (vn(2))^2 + ... + (vn(n))^2.
--c
--          sum = 0
--          do k = 2,n
--            sum = sum+vn(k)**2
--          enddo ! k
--c
--c
--c         Calculate scal.
--c
--          if(sum .eq. 0) scal = 0
--          if(sum .ne. 0) scal = 2/(1+sum)
--c
--c
--        endif
--c
--c
--c       Calculate fact = scal * transpose(vn) * u.
--c
--        fact = u(1)
--c
--        do k = 2,n
--          fact = fact+vn(k)*u(k)
--        enddo ! k
--c
--        fact = fact*scal
--c
--c
--c       Subtract fact*vn from u, yielding v.
--c
--        v(1) = u(1) - fact
--c
--        do k = 2,n
--          v(k) = u(k) - fact*vn(k)
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_house(n,x,rss,vn,scal)
--c
--c       constructs the vector vn with vn(1) = 1
--c       and the scalar scal such that
--c       H := identity_matrix - scal * vn * transpose(vn) is orthogonal
--c       and Hx = +/- e_1 * the root-sum-square of the entries of x
--c       (H is the Householder matrix corresponding to x).
--c
--c       input:
--c       n -- size of x and vn, though the indexing on vn goes
--c            from 2 to n
--c       x -- vector to reflect into its first component
--c
--c       output:
--c       rss -- first entry of the vector resulting from the application
--c              of the Householder matrix to x;
--c              its absolute value is the root-sum-square
--c              of the entries of x
--c       vn -- entries 2 to n of the Householder vector vn;
--c             vn(1) is assumed to be 1
--c       scal -- scalar multiplying vn * transpose(vn);
--c
--c               scal = 2/(1 + vn(2)^2 + ... + vn(n)^2)
--c               when vn(2), ..., vn(n) don't all vanish;
--c
--c               scal = 0
--c               when vn(2), ..., vn(n) do all vanish
--c               (including when n = 1)
--c
--c       reference:
--c       Golub and Van Loan, "Matrix Computations," 3rd edition,
--c            Johns Hopkins University Press, 1996, Chapter 5.
--c
--        implicit none
--        save
--        integer n,k
--        real*8 x(n),rss,sum,v1,scal,vn(2:*),x1
--c
--c
--        x1 = x(1)
--c
--c
--c       Get out of this routine if n = 1.
--c
--        if(n .eq. 1) then
--          rss = x1
--          scal = 0
--          return
--        endif
--c
--c
--c       Calculate (x(2))^2 + ... (x(n))^2
--c       and the root-sum-square value of the entries in x.
--c
--c
--        sum = 0
--        do k = 2,n
--          sum = sum+x(k)**2
--        enddo ! k
--c
--c
--c       Get out of this routine if sum = 0;
--c       flag this case as such by setting v(2), ..., v(n) all to 0.
--c
--        if(sum .eq. 0) then
--c
--          rss = x1
--          do k = 2,n
--            vn(k) = 0
--          enddo ! k
--          scal = 0
--c
--          return
--c
--        endif
--c
--c
--        rss = x1**2 + sum
--        rss = sqrt(rss)
--c
--c
--c       Determine the first component v1
--c       of the unnormalized Householder vector
--c       v = x - rss * (1 0 0 ... 0 0)^T.
--c
--c       If x1 <= 0, then form x1-rss directly,
--c       since that expression cannot involve any cancellation.
--c
--        if(x1 .le. 0) v1 = x1-rss
--c
--c       If x1 > 0, then use the fact that
--c       x1-rss = -sum / (x1+rss),
--c       in order to avoid potential cancellation.
--c
--        if(x1 .gt. 0) v1 = -sum / (x1+rss)
--c
--c
--c       Compute the vector vn and the scalar scal such that vn(1) = 1
--c       in the Householder transformation
--c       identity_matrix - scal * vn * transpose(vn).
--c
--        do k = 2,n
--          vn(k) = x(k)/v1
--        enddo ! k
--c
--c       scal = 2
--c            / ( vn(1)^2 + vn(2)^2 + ... + vn(n)^2 )
--c
--c            = 2
--c            / ( 1 + vn(2)^2 + ... + vn(n)^2 )
--c
--c            = 2*v(1)^2
--c            / ( v(1)^2 + (v(1)*vn(2))^2 + ... + (v(1)*vn(n))^2 )
--c
--c            = 2*v(1)^2
--c            / ( v(1)^2 + (v(2)^2 + ... + v(n)^2) )
--c
--        scal = 2*v1**2 / (v1**2+sum)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_housemat(n,vn,scal,h)
--c
--c       fills h with the Householder matrix
--c       identity_matrix - scal * vn * transpose(vn).
--c
--c       input:
--c       n -- size of vn and h, though the indexing of vn goes
--c            from 2 to n
--c       vn -- entries 2 to n of the vector vn;
--c             vn(1) is assumed to be 1
--c       scal -- scalar multiplying vn * transpose(vn)
--c
--c       output:
--c       h -- identity_matrix - scal * vn * transpose(vn)
--c
--        implicit none
--        save
--        integer n,j,k
--        real*8 vn(2:*),h(n,n),scal,factor1,factor2
--c
--c
--c       Fill h with the identity matrix.
--c
--        do j = 1,n
--          do k = 1,n
--c
--            if(j .eq. k) h(k,j) = 1
--            if(j .ne. k) h(k,j) = 0
--c
--          enddo ! k
--        enddo ! j
--c
--c
--c       Subtract from h the matrix scal*vn*transpose(vn).
--c
--        do j = 1,n
--          do k = 1,n
--c
--            if(j .eq. 1) factor1 = 1
--            if(j .ne. 1) factor1 = vn(j)
--c
--            if(k .eq. 1) factor2 = 1
--            if(k .ne. 1) factor2 = vn(k)
--c
--            h(k,j) = h(k,j) - scal*factor1*factor2
--c
--          enddo ! k
--        enddo ! j
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idd_id.f b/scipy/linalg/src/id_dist/src/idd_id.f
-deleted file mode 100644
-index 640ff455b..000000000
---- a/scipy/linalg/src/id_dist/src/idd_id.f
-+++ /dev/null
-@@ -1,560 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddp_id computes the ID of a matrix,
--c       to a specified precision.
--c
--c       routine iddr_id computes the ID of a matrix,
--c       to a specified rank.
--c
--c       routine idd_reconid reconstructs a matrix from its ID.
--c
--c       routine idd_copycols collects together selected columns
--c       of a matrix.
--c
--c       routine idd_getcols collects together selected columns
--c       of a matrix specified by a routine for applying the matrix
--c       to arbitrary vectors.
--c
--c       routine idd_reconint constructs p in the ID a = b p,
--c       where the columns of b are a subset of the columns of a,
--c       and p is the projection coefficient matrix,
--c       given list, krank, and proj output by routines iddr_id
--c       or iddp_id.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine iddp_id(eps,m,n,a,krank,list,rnorms)
--c
--c       computes the ID of a, i.e., lists in list the indices
--c       of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                        krank
--c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
--c                         l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon dimensioned epsilon(m,n-krank)
--c       such that the greatest singular value of epsilon
--c       <= the greatest singular value of a * eps.
--c       The present routine stores the krank x (n-krank) matrix proj
--c       in the memory initially occupied by a.
--c
--c       input:
--c       eps -- relative precision of the resulting ID
--c       m -- first dimension of a
--c       n -- second dimension of a, as well as the dimension required
--c            of list
--c       a -- matrix to be ID'd
--c
--c       output:
--c       a -- the first krank*(n-krank) elements of a constitute
--c            the krank x (n-krank) interpolation matrix proj
--c       krank -- numerical rank
--c       list -- list of the indices of the krank columns of a
--c               through which the other columns of a are expressed;
--c               also, list describes the permutation of proj
--c               required to reconstruct a as indicated in (*) above
--c       rnorms -- absolute values of the entries on the diagonal
--c                 of the triangular matrix used to compute the ID
--c                 (these may be used to check the stability of the ID)
--c
--c       _N.B._: This routine changes a.
--c
--c       reference:
--c       Cheng, Gimbutas, Martinsson, Rokhlin, "On the compression of
--c            low-rank matrices," SIAM Journal on Scientific Computing,
--c            26 (4): 1389-1404, 2005.
--c
--        implicit none
--        integer m,n,krank,k,list(n),iswap
--        real*8 a(m,n),eps,rnorms(n)
--c
--c
--c       QR decompose a.
--c
--        call iddp_qrpiv(eps,m,n,a,krank,list,rnorms)
--c
--c
--c       Build the list of columns chosen in a
--c       by multiplying together the permutations in list,
--c       with the permutation swapping 1 and list(1) taken rightmost
--c       in the product, that swapping 2 and list(2) taken next
--c       rightmost, ..., that swapping krank and list(krank) taken
--c       leftmost.
--c
--        do k = 1,n
--          rnorms(k) = k
--        enddo ! k
--c
--        if(krank .gt. 0) then
--          do k = 1,krank
--c
--c           Swap rnorms(k) and rnorms(list(k)).
--c
--            iswap = rnorms(k)
--            rnorms(k) = rnorms(list(k))
--            rnorms(list(k)) = iswap
--c
--          enddo ! k
--        endif
--c
--        do k = 1,n
--          list(k) = rnorms(k)
--        enddo ! k
--c
--c
--c       Fill rnorms for the output.
--c
--        if(krank .gt. 0) then
--c
--          do k = 1,krank
--            rnorms(k) = a(k,k)
--          enddo ! k
--c
--        endif
--c
--c
--c       Backsolve for proj, storing it at the beginning of a.
--c
--        if(krank .gt. 0) then
--          call idd_lssolve(m,n,a,krank)
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddr_id(m,n,a,krank,list,rnorms)
--c
--c       computes the ID of a, i.e., lists in list the indices
--c       of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                        krank
--c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
--c                         l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
--c       whose norm is (hopefully) minimized by the pivoting procedure.
--c       The present routine stores the krank x (n-krank) matrix proj
--c       in the memory initially occupied by a.
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a, as well as the dimension required
--c            of list
--c       a -- matrix to be ID'd
--c       krank -- desired rank of the output matrix
--c                (please note that if krank > m or krank > n,
--c                then the rank of the output matrix will be
--c                less than krank)
--c
--c       output:
--c       a -- the first krank*(n-krank) elements of a constitute
--c            the krank x (n-krank) interpolation matrix proj
--c       list -- list of the indices of the krank columns of a
--c               through which the other columns of a are expressed;
--c               also, list describes the permutation of proj
--c               required to reconstruct a as indicated in (*) above
--c       rnorms -- absolute values of the entries on the diagonal
--c                 of the triangular matrix used to compute the ID
--c                 (these may be used to check the stability of the ID)
--c
--c       _N.B._: This routine changes a.
--c
--c       reference:
--c       Cheng, Gimbutas, Martinsson, Rokhlin, "On the compression of
--c            low-rank matrices," SIAM Journal on Scientific Computing,
--c            26 (4): 1389-1404, 2005.
--c
--        implicit none
--        integer m,n,krank,j,k,list(n),iswap
--        real*8 a(m,n),rnorms(n),ss
--c
--c
--c       QR decompose a.
--c
--        call iddr_qrpiv(m,n,a,krank,list,rnorms)
--c
--c
--c       Build the list of columns chosen in a
--c       by multiplying together the permutations in list,
--c       with the permutation swapping 1 and list(1) taken rightmost
--c       in the product, that swapping 2 and list(2) taken next
--c       rightmost, ..., that swapping krank and list(krank) taken
--c       leftmost.
--c
--        do k = 1,n
--          rnorms(k) = k
--        enddo ! k
--c
--        if(krank .gt. 0) then
--          do k = 1,krank
--c
--c           Swap rnorms(k) and rnorms(list(k)).
--c
--            iswap = rnorms(k)
--            rnorms(k) = rnorms(list(k))
--            rnorms(list(k)) = iswap
--c
--          enddo ! k
--        endif
--c
--        do k = 1,n
--          list(k) = rnorms(k)
--        enddo ! k
--c
--c
--c       Fill rnorms for the output.
--c
--        ss = 0
--c
--        do k = 1,krank
--          rnorms(k) = a(k,k)
--          ss = ss+rnorms(k)**2
--        enddo ! k
--c
--c
--c       Backsolve for proj, storing it at the beginning of a.
--c
--        if(krank .gt. 0 .and. ss .gt. 0) then
--          call idd_lssolve(m,n,a,krank)
--        endif
--c
--        if(ss .eq. 0) then
--c
--          do k = 1,n
--            do j = 1,m
--c
--              a(j,k) = 0
--c
--            enddo ! j
--          enddo ! k
--c
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_reconid(m,krank,col,n,list,proj,approx)
--c
--c       reconstructs the matrix that the routine iddp_id
--c       or iddr_id has decomposed, using the columns col
--c       of the reconstructed matrix whose indices are listed in list,
--c       in addition to the interpolation matrix proj.
--c
--c       input:
--c       m -- first dimension of cols and approx
--c       krank -- first dimension of cols and proj; also,
--c                n-krank is the second dimension of proj
--c       col -- columns of the matrix to be reconstructed
--c       n -- second dimension of approx; also,
--c            n-krank is the second dimension of proj
--c       list(k) -- index of col(1:m,k) in the reconstructed matrix
--c                  when k <= krank; in general, list describes
--c                  the permutation required for reconstruction
--c                  via cols and proj
--c       proj -- interpolation matrix
--c
--c       output:
--c       approx -- reconstructed matrix
--c
--        implicit none
--        integer m,n,krank,j,k,l,list(n)
--        real*8 col(m,krank),proj(krank,n-krank),approx(m,n)
--c
--c
--        do j = 1,m
--          do k = 1,n
--c
--            approx(j,list(k)) = 0
--c
--c           Add in the contributions due to the identity matrix.
--c
--            if(k .le. krank) then
--              approx(j,list(k)) = approx(j,list(k)) + col(j,k)
--            endif
--c
--c           Add in the contributions due to proj.
--c
--            if(k .gt. krank) then
--              if(krank .gt. 0) then
--c
--                do l = 1,krank
--                  approx(j,list(k)) = approx(j,list(k))
--     1                              + col(j,l)*proj(l,k-krank)
--                enddo ! l
--c
--              endif
--            endif
--c
--          enddo ! k
--        enddo ! j
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_lssolve(m,n,a,krank)
--c
--c       backsolves for proj satisfying R_11 proj ~ R_12,
--c       where R_11 = a(1:krank,1:krank)
--c       and R_12 = a(1:krank,krank+1:n).
--c       This routine overwrites the beginning of a with proj.
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a; also,
--c            n-krank is the second dimension of proj
--c       a -- trapezoidal input matrix
--c       krank -- first dimension of proj; also,
--c                n-krank is the second dimension of proj
--c
--c       output:
--c       a -- the first krank*(n-krank) elements of a constitute
--c            the krank x (n-krank) matrix proj
--c
--        implicit none
--        integer m,n,krank,j,k,l
--        real*8 a(m,n),sum
--c
--c
--c       Overwrite a(1:krank,krank+1:n) with proj.
--c
--        do k = 1,n-krank
--          do j = krank,1,-1
--c
--            sum = 0
--c
--            do l = j+1,krank
--              sum = sum+a(j,l)*a(l,krank+k)
--            enddo ! l
--c
--            a(j,krank+k) = a(j,krank+k)-sum
--c
--c           Make sure that the entry in proj won't be too big;
--c           set the entry to 0 when roundoff would make it too big
--c           (in which case a(j,j) is so small that the contribution
--c           from this entry in proj to the overall matrix approximation
--c           is supposed to be negligible).
--c
--            if(abs(a(j,krank+k)) .lt. 2**20*abs(a(j,j))) then
--              a(j,krank+k) = a(j,krank+k)/a(j,j)
--            else
--              a(j,krank+k) = 0
--            endif
--c
--          enddo ! j
--        enddo ! k
--c
--c
--c       Move proj from a(1:krank,krank+1:n) to the beginning of a.
--c
--        call idd_moverup(m,n,krank,a)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_moverup(m,n,krank,a)
--c
--c       moves the krank x (n-krank) matrix in a(1:krank,krank+1:n),
--c       where a is initially dimensioned m x n, to the beginning of a.
--c       (This is not the most natural way to code the move,
--c       but one of my usually well-behaved compilers chokes
--c       on more natural ways.)
--c
--c       input:
--c       m -- initial first dimension of a
--c       n -- initial second dimension of a
--c       krank -- number of rows to move
--c       a -- m x n matrix whose krank x (n-krank) block
--c            a(1:krank,krank+1:n) is to be moved
--c
--c       output:
--c       a -- array starting with the moved krank x (n-krank) block
--c
--        implicit none
--        integer m,n,krank,j,k
--        real*8 a(m*n)
--c
--c
--        do k = 1,n-krank
--          do j = 1,krank
--            a(j+krank*(k-1)) = a(j+m*(krank+k-1))
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,
--     1                         col,x)
--c
--c       collects together the columns of the matrix a indexed by list
--c       into the matrix col, where routine matvec applies a
--c       to an arbitrary vector.
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       matvec -- routine which applies a to an arbitrary vector;
--c                 this routine must have a calling sequence of the form
--c
--c                 matvec(m,x,n,y,p1,p2,p3,p4)
--c
--c                 where m is the length of x,
--c                 x is the vector to which the matrix is to be applied,
--c                 n is the length of y,
--c                 y is the product of the matrix and x,
--c                 and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvec
--c       p2 -- parameter to be passed to routine matvec
--c       p3 -- parameter to be passed to routine matvec
--c       p4 -- parameter to be passed to routine matvec
--c       krank -- number of columns to be extracted
--c       list -- indices of the columns to be extracted
--c
--c       output:
--c       col -- columns of a indexed by list
--c
--c       work:
--c       x -- must be at least n real*8 elements long
--c
--        implicit none
--        integer m,n,krank,list(krank),j,k
--        real*8 col(m,krank),x(n),p1,p2,p3,p4
--        external matvec
--c
--c
--        do j = 1,krank
--c
--          do k = 1,n
--            x(k) = 0
--          enddo ! k
--c
--          x(list(j)) = 1
--c
--          call matvec(n,x,m,col(1,j),p1,p2,p3,p4)
--c
--        enddo ! j
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_reconint(n,list,krank,proj,p)
--c
--c       constructs p in the ID a = b p,
--c       where the columns of b are a subset of the columns of a,
--c       and p is the projection coefficient matrix,
--c       given list, krank, and proj output
--c       by routines iddp_id or iddr_id.
--c
--c       input:
--c       n -- part of the second dimension of proj and p
--c       list -- list of columns retained from the original matrix
--c               in the ID
--c       krank -- rank of the ID
--c       proj -- matrix of projection coefficients in the ID
--c
--c       output:
--c       p -- projection matrix in the ID
--c
--        implicit none
--        integer n,krank,list(n),j,k
--        real*8 proj(krank,n-krank),p(krank,n)
--c
--c
--        do k = 1,krank
--          do j = 1,n
--c
--            if(j .le. krank) then
--              if(j .eq. k) p(k,list(j)) = 1
--              if(j .ne. k) p(k,list(j)) = 0
--            endif
--c
--            if(j .gt. krank) then
--              p(k,list(j)) = proj(k,j-krank)
--            endif
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_copycols(m,n,a,krank,list,col)
--c
--c       collects together the columns of the matrix a indexed by list
--c       into the matrix col.
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       a -- matrix whose columns are to be extracted
--c       krank -- number of columns to be extracted
--c       list -- indices of the columns to be extracted
--c
--c       output:
--c       col -- columns of a indexed by list
--c
--        implicit none
--        integer m,n,krank,list(krank),j,k
--        real*8 a(m,n),col(m,krank)
--c
--c
--        do k = 1,krank
--          do j = 1,m
--c
--            col(j,k) = a(j,list(k))
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idd_id2svd.f b/scipy/linalg/src/id_dist/src/idd_id2svd.f
-deleted file mode 100644
-index 42e1f23cd..000000000
---- a/scipy/linalg/src/id_dist/src/idd_id2svd.f
-+++ /dev/null
-@@ -1,384 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idd_id2svd converts an approximation to a matrix
--c       in the form of an ID to an approximation in the form of an SVD.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idd_id2svd(m,krank,b,n,list,proj,u,v,s,ier,w)
--c
--c       converts an approximation to a matrix in the form of an ID
--c       to an approximation in the form of an SVD.
--c
--c       input:
--c       m -- first dimension of b
--c       krank -- rank of the ID
--c       b -- columns of the original matrix in the ID
--c       list -- list of columns chosen from the original matrix
--c               in the ID
--c       n -- length of list and part of the second dimension of proj
--c       proj -- projection coefficients in the ID
--c
--c       output:
--c       u -- left singular vectors
--c       v -- right singular vectors
--c       s -- singular values
--c       ier -- 0 when the routine terminates successfully;
--c              nonzero otherwise
--c
--c       work:
--c       w -- must be at least (krank+1)*(m+3*n)+26*krank**2 real*8
--c            elements long
--c
--c       _N.B._: This routine destroys b.
--c
--        implicit none
--        integer m,krank,n,list(n),iwork,lwork,ip,lp,it,lt,ir,lr,
--     1          ir2,lr2,ir3,lr3,iind,lind,iindt,lindt,lw,ier
--        real*8 b(m,krank),proj(krank,n-krank),u(m,krank),v(n,krank),
--     1         w((krank+1)*(m+3*n)+26*krank**2),s(krank)
--c
--c
--        lw = 0
--c
--        iwork = lw+1
--        lwork = 25*krank**2
--        lw = lw+lwork
--c
--        ip = lw+1
--        lp = krank*n
--        lw = lw+lp
--c
--        it = lw+1
--        lt = n*krank
--        lw = lw+lt
--c
--        ir = lw+1
--        lr = krank*n
--        lw = lw+lr
--c
--        ir2 = lw+1
--        lr2 = krank*m
--        lw = lw+lr2
--c
--        ir3 = lw+1
--        lr3 = krank*krank
--        lw = lw+lr3
--c
--        iind = lw+1
--        lind = n/2+1
--        lw = lw+1
--c
--        iindt = lw+1
--        lindt = m/2+1
--        lw = lw+1
--c
--c
--        call idd_id2svd0(m,krank,b,n,list,proj,u,v,s,ier,
--     1                   w(iwork),w(ip),w(it),w(ir),w(ir2),w(ir3),
--     2                   w(iind),w(iindt))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_id2svd0(m,krank,b,n,list,proj,u,v,s,ier,
--     1                         work,p,t,r,r2,r3,ind,indt)
--c
--c       routine idd_id2svd serves as a memory wrapper
--c       for the present routine (please see routine idd_id2svd
--c       for further documentation).
--c
--        implicit none
--c
--        character*1 jobz
--        integer m,n,krank,list(n),ind(n),indt(m),iftranspose,
--     1          lwork,ldu,ldvt,ldr,info,j,k,ier
--        real*8 b(m,krank),proj(krank,n-krank),p(krank,n),
--     1         r(krank,n),r2(krank,m),t(n,krank),r3(krank,krank),
--     2         u(m,krank),v(n,krank),s(krank),work(25*krank**2)
--c
--c
--c
--        ier = 0
--c
--c
--c
--c       Construct the projection matrix p from the ID.
--c
--        call idd_reconint(n,list,krank,proj,p)
--c
--c
--c
--c       Compute a pivoted QR decomposition of b.
--c
--        call iddr_qrpiv(m,krank,b,krank,ind,r)
--c
--c
--c       Extract r from the QR decomposition.
--c
--        call idd_rinqr(m,krank,b,krank,r)
--c
--c
--c       Rearrange r according to ind.
--c
--        call idd_rearr(krank,ind,krank,krank,r)
--c
--c
--c
--c       Transpose p to obtain t.
--c
--        call idd_mattrans(krank,n,p,t)
--c
--c
--c       Compute a pivoted QR decomposition of t.
--c
--        call iddr_qrpiv(n,krank,t,krank,indt,r2)
--c
--c
--c       Extract r2 from the QR decomposition.
--c
--        call idd_rinqr(n,krank,t,krank,r2)
--c
--c
--c       Rearrange r2 according to indt.
--c
--        call idd_rearr(krank,indt,krank,krank,r2)
--c
--c
--c
--c       Multiply r and r2^T to obtain r3.
--c
--        call idd_matmultt(krank,krank,r,krank,r2,r3)
--c
--c
--c
--c       Use LAPACK to SVD r3.
--c
--        jobz = 'S'
--        ldr = krank
--        lwork = 25*krank**2-krank**2-4*krank
--        ldu = krank
--        ldvt = krank
--c
--        call dgesdd(jobz,krank,krank,r3,ldr,s,work,ldu,r,ldvt,
--     1              work(krank**2+4*krank+1),lwork,
--     2              work(krank**2+1),info)
--c
--        if(info .ne. 0) then
--          ier = info
--          return
--        endif
--c
--c
--c
--c       Multiply the u from r3 from the left by the q from b
--c       to obtain the u for a.
--c
--        do k = 1,krank
--c
--          do j = 1,krank
--            u(j,k) = work(j+krank*(k-1))
--          enddo ! j
--c
--          do j = krank+1,m
--            u(j,k) = 0
--          enddo ! j
--c
--        enddo ! k
--c
--        iftranspose = 0
--        call idd_qmatmat(iftranspose,m,krank,b,krank,krank,u,r2)
--c
--c
--c
--c       Transpose r to obtain r2.
--c
--        call idd_mattrans(krank,krank,r,r2)
--c
--c
--c       Multiply the v from r3 from the left by the q from p^T
--c       to obtain the v for a.
--c
--        do k = 1,krank
--c
--          do j = 1,krank
--            v(j,k) = r2(j,k)
--          enddo ! j
--c
--          do j = krank+1,n
--            v(j,k) = 0
--          enddo ! j
--c
--        enddo ! k
--c
--        iftranspose = 0
--        call idd_qmatmat(iftranspose,n,krank,t,krank,krank,v,r2)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_mattrans(m,n,a,at)
--c
--c       transposes a to obtain at.
--c
--c       input:
--c       m -- first dimension of a, and second dimension of at
--c       n -- second dimension of a, and first dimension of at
--c       a -- matrix to be transposed
--c
--c       output:
--c       at -- transpose of a
--c
--        implicit none
--        integer m,n,j,k
--        real*8 a(m,n),at(n,m)
--c
--c
--        do k = 1,n
--          do j = 1,m
--            at(k,j) = a(j,k)
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_matmultt(l,m,a,n,b,c)
--c
--c       multiplies a and b^T to obtain c.
--c
--c       input:
--c       l -- first dimension of a and c
--c       m -- second dimension of a and b
--c       a -- leftmost matrix in the product c = a b^T
--c       n -- first dimension of b and second dimension of c
--c       b -- rightmost matrix in the product c = a b^T
--c
--c       output:
--c       c -- product of a and b^T
--c
--        implicit none
--        integer l,m,n,i,j,k
--        real*8 a(l,m),b(n,m),c(l,n),sum
--c
--c
--        do i = 1,l
--          do k = 1,n
--c
--            sum = 0
--c
--            do j = 1,m
--              sum = sum+a(i,j)*b(k,j)
--            enddo ! j
--c
--            c(i,k) = sum
--c
--          enddo ! k
--        enddo ! i
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_rearr(krank,ind,m,n,a)
--c
--c       rearranges a according to ind obtained
--c       from routines iddr_qrpiv or iddp_qrpiv,
--c       assuming that a = q r, where q and r are from iddr_qrpiv
--c       or iddp_qrpiv.
--c
--c       input:
--c       krank -- rank obtained from routine iddp_qrpiv,
--c                or provided to routine iddr_qrpiv
--c       ind -- indexing array obtained from routine iddr_qrpiv
--c              or iddp_qrpiv
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       a -- matrix to be rearranged
--c
--c       output:
--c       a -- rearranged matrix
--c
--        implicit none
--        integer k,krank,m,n,j,ind(krank)
--        real*8 rswap,a(m,n)
--c
--c
--        do k = krank,1,-1
--          do j = 1,m
--c
--            rswap = a(j,k)
--            a(j,k) = a(j,ind(k))
--            a(j,ind(k)) = rswap
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_rinqr(m,n,a,krank,r)
--c
--c       extracts R in the QR decomposition specified by the output a
--c       of the routine iddr_qrpiv or iddp_qrpiv.
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a and r
--c       a -- output of routine iddr_qrpiv or iddp_qrpiv
--c       krank -- rank output by routine iddp_qrpiv (or specified
--c                to routine iddr_qrpiv)
--c
--c       output:
--c       r -- triangular factor in the QR decomposition specified
--c            by the output a of the routine iddr_qrpiv or iddp_qrpiv
--c
--        implicit none
--        integer m,n,j,k,krank
--        real*8 a(m,n),r(krank,n)
--c
--c
--c       Copy a into r and zero out the appropriate
--c       Householder vectors that are stored in one triangle of a.
--c
--        do k = 1,n
--          do j = 1,krank
--            r(j,k) = a(j,k)
--          enddo ! j
--        enddo ! k
--c
--        do k = 1,n
--          if(k .lt. krank) then
--            do j = k+1,krank
--              r(j,k) = 0
--            enddo ! j
--          endif
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idd_qrpiv.f b/scipy/linalg/src/id_dist/src/idd_qrpiv.f
-deleted file mode 100644
-index b1dd88e15..000000000
---- a/scipy/linalg/src/id_dist/src/idd_qrpiv.f
-+++ /dev/null
-@@ -1,893 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddp_qrpiv computes the pivoted QR decomposition
--c       of a matrix via Householder transformations,
--c       stopping at a specified precision of the decomposition.
--c
--c       routine iddr_qrpiv computes the pivoted QR decomposition
--c       of a matrix via Householder transformations,
--c       stopping at a specified rank of the decomposition.
--c
--c       routine idd_qmatvec applies to a single vector
--c       the Q matrix (or its transpose) in the QR decomposition
--c       of a matrix, as described by the output of iddp_qrpiv
--c       or iddr_qrpiv. If you're concerned about efficiency
--c       and want to apply Q (or its transpose) to multiple vectors,
--c       use idd_qmatmat instead.
--c
--c       routine idd_qmatmat applies
--c       to multiple vectors collected together
--c       as a matrix the Q matrix (or its transpose)
--c       in the QR decomposition of a matrix, as described
--c       by the output of iddp_qrpiv or iddr_qrpiv. If you don't want
--c       to provide a work array and want to apply Q (or its transpose)
--c       to a single vector, use idd_qmatvec instead.
--c
--c       routine idd_qinqr reconstructs the Q matrix
--c       in a QR decomposition from the data generated
--c       by iddp_qrpiv or iddr_qrpiv.
--c
--c       routine idd_permmult multiplies together a bunch
--c       of permutations.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--
--        subroutine idd_permmult(m,ind,n,indprod)
--c
--c       multiplies together the series of permutations in ind.
--c
--c       input:
--c       m -- length of ind
--c       ind(k) -- number of the slot with which to swap
--c                 the k^th slot
--c       n -- length of indprod and indprodinv
--c
--c       output:
--c       indprod -- product of the permutations in ind,
--c                  with the permutation swapping 1 and ind(1)
--c                  taken leftmost in the product,
--c                  that swapping 2 and ind(2) taken next leftmost,
--c                  ..., that swapping krank and ind(krank)
--c                  taken rightmost; indprod(k) is the number
--c                  of the slot with which to swap the k^th slot
--c                  in the product permutation
--c
--        implicit none
--        integer m,n,ind(m),indprod(n),k,iswap
--c
--c
--        do k = 1,n
--          indprod(k) = k
--        enddo ! k
--c
--        do k = m,1,-1
--c
--c         Swap indprod(k) and indprod(ind(k)).
--c
--          iswap = indprod(k)
--          indprod(k) = indprod(ind(k))
--          indprod(ind(k)) = iswap
--c
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_qinqr(m,n,a,krank,q)
--c
--c       constructs the matrix q from iddp_qrpiv or iddr_qrpiv
--c       (see the routine iddp_qrpiv or iddr_qrpiv
--c       for more information).
--c
--c       input:
--c       m -- first dimension of a; also, right now, q is m x m
--c       n -- second dimension of a
--c       a -- matrix output by iddp_qrpiv or iddr_qrpiv
--c            (and denoted the same there)
--c       krank -- numerical rank output by iddp_qrpiv or iddr_qrpiv
--c                (and denoted the same there)
--c
--c       output:
--c       q -- orthogonal matrix implicitly specified by the data in a
--c            from iddp_qrpiv or iddr_qrpiv
--c
--c       Note:
--c       Right now, this routine simply multiplies
--c       one after another the krank Householder matrices
--c       in the full QR decomposition of a,
--c       in order to obtain the complete m x m Q factor in the QR.
--c       This routine should instead use the following
--c       (more elaborate but more efficient) scheme
--c       to construct a q dimensioned q(krank,m); this scheme
--c       was introduced by Robert Schreiber and Charles Van Loan
--c       in "A Storage-Efficient _WY_ Representation
--c       for Products of Householder Transformations,"
--c       _SIAM Journal on Scientific and Statistical Computing_,
--c       Vol. 10, No. 1, pp. 53-57, January, 1989:
--c
--c       Theorem 1. Suppose that Q = _1_ + YTY^T is
--c       an m x m orthogonal real matrix,
--c       where Y is an m x k real matrix
--c       and T is a k x k upper triangular real matrix.
--c       Suppose also that P = _1_ - 2 v v^T is
--c       a real Householder matrix and Q_+ = QP,
--c       where v is an m x 1 real vector,
--c       normalized so that v^T v = 1.
--c       Then, Q_+ = _1_ + Y_+ T_+ Y_+^T,
--c       where Y_+ = (Y v) is the m x (k+1) matrix
--c       formed by adjoining v to the right of Y,
--c                 ( T   z )
--c       and T_+ = (       ) is
--c                 ( 0  -2 )
--c       the (k+1) x (k+1) upper triangular matrix
--c       formed by adjoining z to the right of T
--c       and the vector (0 ... 0 -2) with k zeroes below (T z),
--c       where z = -2 T Y^T v.
--c
--c       Now, suppose that A is a (rank-deficient) matrix
--c       whose complete QR decomposition has
--c       the blockwise partioned form
--c           ( Q_11 Q_12 ) ( R_11 R_12 )   ( Q_11 )
--c       A = (           ) (           ) = (      ) (R_11 R_12).
--c           ( Q_21 Q_22 ) (  0    0   )   ( Q_21 )
--c       Then, the only blocks of the orthogonal factor
--c       in the above QR decomposition of A that matter are
--c                                                        ( Q_11 )
--c       Q_11 and Q_21, _i.e._, only the block of columns (      )
--c                                                        ( Q_21 )
--c       interests us.
--c       Suppose in addition that Q_11 is a k x k matrix,
--c       Q_21 is an (m-k) x k matrix, and that
--c       ( Q_11 Q_12 )
--c       (           ) = _1_ + YTY^T, as in Theorem 1 above.
--c       ( Q_21 Q_22 )
--c       Then, Q_11 = _1_ + Y_1 T Y_1^T
--c       and Q_21 = Y_2 T Y_1^T,
--c       where Y_1 is the k x k matrix and Y_2 is the (m-k) x k matrix
--c                   ( Y_1 )
--c       so that Y = (     ).
--c                   ( Y_2 )
--c
--c       So, you can calculate T and Y via the above recursions,
--c       and then use these to compute the desired Q_11 and Q_21.
--c
--c
--        implicit none
--        integer m,n,krank,j,k,mm,ifrescal
--        real*8 a(m,n),q(m,m),scal
--c
--c
--c       Zero all of the entries of q.
--c
--        do k = 1,m
--          do j = 1,m
--            q(j,k) = 0
--          enddo ! j
--        enddo ! k
--c
--c
--c       Place 1's along the diagonal of q.
--c
--        do k = 1,m
--          q(k,k) = 1
--        enddo ! k
--c
--c
--c       Apply the krank Householder transformations stored in a.
--c
--        do k = krank,1,-1
--          do j = k,m
--            mm = m-k+1
--            ifrescal = 1
--            if(k .lt. m)
--     1       call idd_houseapp(mm,a(k+1,k),q(k,j),ifrescal,scal,q(k,j))
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_qmatvec(iftranspose,m,n,a,krank,v)
--c
--c       applies to a single vector the Q matrix (or its transpose)
--c       which the routine iddp_qrpiv or iddr_qrpiv has stored
--c       in a triangle of the matrix it produces (stored, incidentally,
--c       as data for applying a bunch of Householder reflections).
--c       Use the routine qmatmat to apply the Q matrix
--c       (or its transpose)
--c       to a bunch of vectors collected together as a matrix,
--c       if you're concerned about efficiency.
--c
--c       input:
--c       iftranspose -- set to 0 for applying Q;
--c                      set to 1 for applying the transpose of Q
--c       m -- first dimension of a and length of v
--c       n -- second dimension of a
--c       a -- data describing the qr decomposition of a matrix,
--c            as produced by iddp_qrpiv or iddr_qrpiv
--c       krank -- numerical rank
--c       v -- vector to which Q (or its transpose) is to be applied
--c
--c       output:
--c       v -- vector to which Q (or its transpose) has been applied
--c
--        implicit none
--        save
--        integer m,n,krank,k,ifrescal,mm,iftranspose
--        real*8 a(m,n),v(m),scal
--c
--c
--        ifrescal = 1
--c
--c
--        if(iftranspose .eq. 0) then
--c
--          do k = krank,1,-1
--            mm = m-k+1
--            if(k .lt. m)
--     1       call idd_houseapp(mm,a(k+1,k),v(k),ifrescal,scal,v(k))
--          enddo ! k
--c
--        endif
--c
--c
--        if(iftranspose .eq. 1) then
--c
--          do k = 1,krank
--            mm = m-k+1
--            if(k .lt. m)
--     1       call idd_houseapp(mm,a(k+1,k),v(k),ifrescal,scal,v(k))
--          enddo ! k
--c
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_qmatmat(iftranspose,m,n,a,krank,l,b,work)
--c
--c       applies to a bunch of vectors collected together as a matrix
--c       the Q matrix (or its transpose) which the routine iddp_qrpiv or
--c       iddr_qrpiv has stored in a triangle of the matrix it produces
--c       (stored, incidentally, as data for applying a bunch
--c       of Householder reflections).
--c       Use the routine qmatvec to apply the Q matrix
--c       (or its transpose)
--c       to a single vector, if you'd rather not provide a work array.
--c
--c       input:
--c       iftranspose -- set to 0 for applying Q;
--c                      set to 1 for applying the transpose of Q
--c       m -- first dimension of both a and b
--c       n -- second dimension of a
--c       a -- data describing the qr decomposition of a matrix,
--c            as produced by iddp_qrpiv or iddr_qrpiv
--c       krank -- numerical rank
--c       l -- second dimension of b
--c       b -- matrix to which Q (or its transpose) is to be applied
--c
--c       output:
--c       b -- matrix to which Q (or its transpose) has been applied
--c
--c       work:
--c       work -- must be at least krank real*8 elements long
--c
--        implicit none
--        save
--        integer l,m,n,krank,j,k,ifrescal,mm,iftranspose
--        real*8 a(m,n),b(m,l),work(krank)
--c
--c
--        if(iftranspose .eq. 0) then
--c
--c
--c         Handle the first iteration, j = 1,
--c         calculating all scals (ifrescal = 1).
--c
--          ifrescal = 1
--c
--          j = 1
--c
--          do k = krank,1,-1
--            if(k .lt. m) then
--              mm = m-k+1
--              call idd_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
--     1                          work(k),b(k,j))
--            endif
--          enddo ! k
--c
--c
--          if(l .gt. 1) then
--c
--c           Handle the other iterations, j > 1,
--c           using the scals just computed (ifrescal = 0).
--c
--            ifrescal = 0
--c
--            do j = 2,l
--c
--              do k = krank,1,-1
--                if(k .lt. m) then
--                  mm = m-k+1
--                  call idd_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
--     1                              work(k),b(k,j))
--                endif
--              enddo ! k
--c
--            enddo ! j
--c
--          endif ! j .gt. 1
--c
--c
--        endif ! iftranspose .eq. 0
--c
--c
--        if(iftranspose .eq. 1) then
--c
--c
--c         Handle the first iteration, j = 1,
--c         calculating all scals (ifrescal = 1).
--c
--          ifrescal = 1
--c
--          j = 1
--c
--          do k = 1,krank
--            if(k .lt. m) then
--              mm = m-k+1
--              call idd_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
--     1                          work(k),b(k,j))
--            endif
--          enddo ! k
--c
--c
--          if(l .gt. 1) then
--c
--c           Handle the other iterations, j > 1,
--c           using the scals just computed (ifrescal = 0).
--c
--            ifrescal = 0
--c
--            do j = 2,l
--c
--              do k = 1,krank
--                if(k .lt. m) then
--                  mm = m-k+1
--                  call idd_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
--     1                              work(k),b(k,j))
--                endif
--              enddo ! k
--c
--            enddo ! j
--c
--          endif ! j .gt. 1
--c
--c
--        endif ! iftranspose .eq. 1
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddp_qrpiv(eps,m,n,a,krank,ind,ss)
--c
--c       computes the pivoted QR decomposition
--c       of the matrix input into a, using Householder transformations,
--c       _i.e._, transforms the matrix a from its input value in
--c       to the matrix out with entry
--c
--c                               m
--c       out(j,indprod(k))  =  Sigma  q(l,j) * in(l,k),
--c                              l=1
--c
--c       for all j = 1, ..., krank, and k = 1, ..., n,
--c
--c       where in = the a from before the routine runs,
--c       out = the a from after the routine runs,
--c       out(j,k) = 0 when j > k (so that out is triangular),
--c       q(1:m,1), ..., q(1:m,krank) are orthonormal,
--c       indprod is the product of the permutations given by ind,
--c       (as computable via the routine permmult,
--c       with the permutation swapping 1 and ind(1) taken leftmost
--c       in the product, that swapping 2 and ind(2) taken next leftmost,
--c       ..., that swapping krank and ind(krank) taken rightmost),
--c       and with the matrix out satisfying
--c
--c                   krank
--c       in(j,k)  =  Sigma  q(j,l) * out(l,indprod(k))  +  epsilon(j,k),
--c                    l=1
--c
--c       for all j = 1, ..., m, and k = 1, ..., n,
--c
--c       for some matrix epsilon such that
--c       the root-sum-square of the entries of epsilon
--c       <= the root-sum-square of the entries of in * eps.
--c       Well, technically, this routine outputs the Householder vectors
--c       (or, rather, their second through last entries)
--c       in the part of a that is supposed to get zeroed, that is,
--c       in a(j,k) with m >= j > k >= 1.
--c
--c       input:
--c       eps -- relative precision of the resulting QR decomposition
--c       m -- first dimension of a and q
--c       n -- second dimension of a
--c       a -- matrix whose QR decomposition gets computed
--c
--c       output:
--c       a -- triangular (R) factor in the QR decompositon
--c            of the matrix input into the same storage locations,
--c            with the Householder vectors stored in the part of a
--c            that would otherwise consist entirely of zeroes, that is,
--c            in a(j,k) with m >= j > k >= 1
--c       krank -- numerical rank
--c       ind(k) -- index of the k^th pivot vector;
--c                 the following code segment will correctly rearrange
--c                 the product b of q and the upper triangle of out
--c                 so that b matches the input matrix in
--c                 to relative precision eps:
--c
--c                 copy the non-rearranged product of q and out into b
--c                 set k to krank
--c                 [start of loop]
--c                   swap b(1:m,k) and b(1:m,ind(k))
--c                   decrement k by 1
--c                 if k > 0, then go to [start of loop]
--c
--c       work:
--c       ss -- must be at least n real*8 words long
--c
--c       _N.B._: This routine outputs the Householder vectors
--c       (or, rather, their second through last entries)
--c       in the part of a that is supposed to get zeroed, that is,
--c       in a(j,k) with m >= j > k >= 1.
--c
--c       reference:
--c       Golub and Van Loan, "Matrix Computations," 3rd edition,
--c            Johns Hopkins University Press, 1996, Chapter 5.
--c
--        implicit none
--        integer n,m,ind(n),krank,k,j,kpiv,mm,nupdate,ifrescal
--        real*8 a(m,n),ss(n),eps,feps,ssmax,scal,ssmaxin,rswap
--c
--c
--        feps = .1d-16
--c
--c
--c       Compute the sum of squares of the entries in each column of a,
--c       the maximum of all such sums, and find the first pivot
--c       (column with the greatest such sum).
--c
--        ssmax = 0
--        kpiv = 1
--c
--        do k = 1,n
--c
--          ss(k) = 0
--          do j = 1,m
--            ss(k) = ss(k)+a(j,k)**2
--          enddo ! j
--c
--          if(ss(k) .gt. ssmax) then
--            ssmax = ss(k)
--            kpiv = k
--          endif
--c
--        enddo ! k
--c
--        ssmaxin = ssmax
--c
--        nupdate = 0
--c
--c
--c       While ssmax > eps**2*ssmaxin, krank < m, and krank < n,
--c       do the following block of code,
--c       which ends at the statement labeled 2000.
--c
--        krank = 0
-- 1000   continue
--c
--        if(ssmax .le. eps**2*ssmaxin
--     1   .or. krank .ge. m .or. krank .ge. n) goto 2000
--        krank = krank+1
--c
--c
--          mm = m-krank+1
--c
--c
--c         Perform the pivoting.
--c
--          ind(krank) = kpiv
--c
--c         Swap a(1:m,krank) and a(1:m,kpiv).
--c
--          do j = 1,m
--            rswap = a(j,krank)
--            a(j,krank) = a(j,kpiv)
--            a(j,kpiv) = rswap
--          enddo ! j
--c
--c         Swap ss(krank) and ss(kpiv).
--c
--          rswap = ss(krank)
--          ss(krank) = ss(kpiv)
--          ss(kpiv) = rswap
--c
--c
--          if(krank .lt. m) then
--c
--c
--c           Compute the data for the Householder transformation
--c           which will zero a(krank+1,krank), ..., a(m,krank)
--c           when applied to a, replacing a(krank,krank)
--c           with the first entry of the result of the application
--c           of the Householder matrix to a(krank:m,krank),
--c           and storing entries 2 to mm of the Householder vector
--c           in a(krank+1,krank), ..., a(m,krank)
--c           (which otherwise would get zeroed upon application
--c           of the Householder transformation).
--c
--            call idd_house(mm,a(krank,krank),a(krank,krank),
--     1                     a(krank+1,krank),scal)
--            ifrescal = 0
--c
--c
--c           Apply the Householder transformation
--c           to the lower right submatrix of a
--c           with upper leftmost entry at position (krank,krank+1).
--c
--            if(krank .lt. n) then
--              do k = krank+1,n
--                call idd_houseapp(mm,a(krank+1,krank),a(krank,k),
--     1                            ifrescal,scal,a(krank,k))
--              enddo ! k
--            endif
--c
--c
--c           Update the sums-of-squares array ss.
--c
--            do k = krank,n
--              ss(k) = ss(k)-a(krank,k)**2
--            enddo ! k
--c
--c
--c           Find the pivot (column with the greatest sum of squares
--c           of its entries).
--c
--            ssmax = 0
--            kpiv = krank+1
--c
--            if(krank .lt. n) then
--c
--              do k = krank+1,n
--c
--                if(ss(k) .gt. ssmax) then
--                  ssmax = ss(k)
--                  kpiv = k
--                endif
--c
--              enddo ! k
--c
--            endif ! krank .lt. n
--c
--c
--c           Recompute the sums-of-squares and the pivot
--c           when ssmax first falls below
--c           sqrt((1000*feps)^2) * ssmaxin
--c           and when ssmax first falls below
--c           ((1000*feps)^2) * ssmaxin.
--c
--            if(
--     1       (ssmax .lt. sqrt((1000*feps)**2) * ssmaxin
--     2        .and. nupdate .eq. 0) .or.
--     3       (ssmax .lt. ((1000*feps)**2) * ssmaxin
--     4        .and. nupdate .eq. 1)
--     5      ) then
--c
--              nupdate = nupdate+1
--c
--              ssmax = 0
--              kpiv = krank+1
--c
--              if(krank .lt. n) then
--c
--                do k = krank+1,n
--c
--                  ss(k) = 0
--                  do j = krank+1,m
--                    ss(k) = ss(k)+a(j,k)**2
--                  enddo ! j
--c
--                  if(ss(k) .gt. ssmax) then
--                    ssmax = ss(k)
--                    kpiv = k
--                  endif
--c
--                enddo ! k
--c
--              endif ! krank .lt. n
--c
--            endif
--c
--c
--          endif ! krank .lt. m
--c
--c
--        goto 1000
-- 2000   continue
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddr_qrpiv(m,n,a,krank,ind,ss)
--c
--c       computes the pivoted QR decomposition
--c       of the matrix input into a, using Householder transformations,
--c       _i.e._, transforms the matrix a from its input value in
--c       to the matrix out with entry
--c
--c                               m
--c       out(j,indprod(k))  =  Sigma  q(l,j) * in(l,k),
--c                              l=1
--c
--c       for all j = 1, ..., krank, and k = 1, ..., n,
--c
--c       where in = the a from before the routine runs,
--c       out = the a from after the routine runs,
--c       out(j,k) = 0 when j > k (so that out is triangular),
--c       q(1:m,1), ..., q(1:m,krank) are orthonormal,
--c       indprod is the product of the permutations given by ind,
--c       (as computable via the routine permmult,
--c       with the permutation swapping 1 and ind(1) taken leftmost
--c       in the product, that swapping 2 and ind(2) taken next leftmost,
--c       ..., that swapping krank and ind(krank) taken rightmost),
--c       and with the matrix out satisfying
--c
--c                  min(krank,m,n)
--c       in(j,k)  =     Sigma      q(j,l) * out(l,indprod(k))
--c                       l=1
--c
--c                +  epsilon(j,k),
--c
--c       for all j = 1, ..., m, and k = 1, ..., n,
--c
--c       for some matrix epsilon whose norm is (hopefully) minimized
--c       by the pivoting procedure.
--c       Well, technically, this routine outputs the Householder vectors
--c       (or, rather, their second through last entries)
--c       in the part of a that is supposed to get zeroed, that is,
--c       in a(j,k) with m >= j > k >= 1.
--c
--c       input:
--c       m -- first dimension of a and q
--c       n -- second dimension of a
--c       a -- matrix whose QR decomposition gets computed
--c       krank -- desired rank of the output matrix
--c                (please note that if krank > m or krank > n,
--c                then the rank of the output matrix will be
--c                less than krank)
--c
--c       output:
--c       a -- triangular (R) factor in the QR decompositon
--c            of the matrix input into the same storage locations,
--c            with the Householder vectors stored in the part of a
--c            that would otherwise consist entirely of zeroes, that is,
--c            in a(j,k) with m >= j > k >= 1
--c       ind(k) -- index of the k^th pivot vector;
--c                 the following code segment will correctly rearrange
--c                 the product b of q and the upper triangle of out
--c                 so that b best matches the input matrix in:
--c
--c                 copy the non-rearranged product of q and out into b
--c                 set k to krank
--c                 [start of loop]
--c                   swap b(1:m,k) and b(1:m,ind(k))
--c                   decrement k by 1
--c                 if k > 0, then go to [start of loop]
--c
--c       work:
--c       ss -- must be at least n real*8 words long
--c
--c       _N.B._: This routine outputs the Householder vectors
--c       (or, rather, their second through last entries)
--c       in the part of a that is supposed to get zeroed, that is,
--c       in a(j,k) with m >= j > k >= 1.
--c
--c       reference:
--c       Golub and Van Loan, "Matrix Computations," 3rd edition,
--c            Johns Hopkins University Press, 1996, Chapter 5.
--c
--        implicit none
--        integer n,m,ind(n),krank,k,j,kpiv,mm,nupdate,ifrescal,
--     1          loops,loop
--        real*8 a(m,n),ss(n),ssmax,scal,ssmaxin,rswap,feps
--c
--c
--        feps = .1d-16
--c
--c
--c       Compute the sum of squares of the entries in each column of a,
--c       the maximum of all such sums, and find the first pivot
--c       (column with the greatest such sum).
--c
--        ssmax = 0
--        kpiv = 1
--c
--        do k = 1,n
--c
--          ss(k) = 0
--          do j = 1,m
--            ss(k) = ss(k)+a(j,k)**2
--          enddo ! j
--c
--          if(ss(k) .gt. ssmax) then
--            ssmax = ss(k)
--            kpiv = k
--          endif
--c
--        enddo ! k
--c
--        ssmaxin = ssmax
--c
--        nupdate = 0
--c
--c
--c       Set loops = min(krank,m,n).
--c
--        loops = krank
--        if(m .lt. loops) loops = m
--        if(n .lt. loops) loops = n
--c
--        do loop = 1,loops
--c
--c
--          mm = m-loop+1
--c
--c
--c         Perform the pivoting.
--c
--          ind(loop) = kpiv
--c
--c         Swap a(1:m,loop) and a(1:m,kpiv).
--c
--          do j = 1,m
--            rswap = a(j,loop)
--            a(j,loop) = a(j,kpiv)
--            a(j,kpiv) = rswap
--          enddo ! j
--c
--c         Swap ss(loop) and ss(kpiv).
--c
--          rswap = ss(loop)
--          ss(loop) = ss(kpiv)
--          ss(kpiv) = rswap
--c
--c
--          if(loop .lt. m) then
--c
--c
--c           Compute the data for the Householder transformation
--c           which will zero a(loop+1,loop), ..., a(m,loop)
--c           when applied to a, replacing a(loop,loop)
--c           with the first entry of the result of the application
--c           of the Householder matrix to a(loop:m,loop),
--c           and storing entries 2 to mm of the Householder vector
--c           in a(loop+1,loop), ..., a(m,loop)
--c           (which otherwise would get zeroed upon application
--c           of the Householder transformation).
--c
--            call idd_house(mm,a(loop,loop),a(loop,loop),
--     1                     a(loop+1,loop),scal)
--            ifrescal = 0
--c
--c
--c           Apply the Householder transformation
--c           to the lower right submatrix of a
--c           with upper leftmost entry at position (loop,loop+1).
--c
--            if(loop .lt. n) then
--              do k = loop+1,n
--                call idd_houseapp(mm,a(loop+1,loop),a(loop,k),
--     1                            ifrescal,scal,a(loop,k))
--              enddo ! k
--            endif
--c
--c
--c           Update the sums-of-squares array ss.
--c
--            do k = loop,n
--              ss(k) = ss(k)-a(loop,k)**2
--            enddo ! k
--c
--c
--c           Find the pivot (column with the greatest sum of squares
--c           of its entries).
--c
--            ssmax = 0
--            kpiv = loop+1
--c
--            if(loop .lt. n) then
--c
--              do k = loop+1,n
--c
--                if(ss(k) .gt. ssmax) then
--                  ssmax = ss(k)
--                  kpiv = k
--                endif
--c
--              enddo ! k
--c
--            endif ! loop .lt. n
--c
--c
--c           Recompute the sums-of-squares and the pivot
--c           when ssmax first falls below
--c           sqrt((1000*feps)^2) * ssmaxin
--c           and when ssmax first falls below
--c           ((1000*feps)^2) * ssmaxin.
--c
--            if(
--     1       (ssmax .lt. sqrt((1000*feps)**2) * ssmaxin
--     2        .and. nupdate .eq. 0) .or.
--     3       (ssmax .lt. ((1000*feps)**2) * ssmaxin
--     4        .and. nupdate .eq. 1)
--     5      ) then
--c
--              nupdate = nupdate+1
--c
--              ssmax = 0
--              kpiv = loop+1
--c
--              if(loop .lt. n) then
--c
--                do k = loop+1,n
--c
--                  ss(k) = 0
--                  do j = loop+1,m
--                    ss(k) = ss(k)+a(j,k)**2
--                  enddo ! j
--c
--                  if(ss(k) .gt. ssmax) then
--                    ssmax = ss(k)
--                    kpiv = k
--                  endif
--c
--                enddo ! k
--c
--              endif ! loop .lt. n
--c
--            endif
--c
--c
--          endif ! loop .lt. m
--c
--c
--        enddo ! loop
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idd_sfft.f b/scipy/linalg/src/id_dist/src/idd_sfft.f
-deleted file mode 100644
-index e46045ac2..000000000
---- a/scipy/linalg/src/id_dist/src/idd_sfft.f
-+++ /dev/null
-@@ -1,443 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idd_sffti initializes routine idd_sfft.
--c
--c       routine idd_sfft rapidly computes a subset of the entries
--c       of the DFT of a vector, composed with permutation matrices
--c       both on input and on output.
--c
--c       routine idd_ldiv finds the greatest integer less than or equal
--c       to a specified integer, that is divisible by another (larger)
--c       specified integer.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idd_ldiv(l,n,m)
--c
--c       finds the greatest integer less than or equal to l
--c       that divides n.
--c
--c       input:
--c       l -- integer at least as great as m
--c       n -- integer divisible by m
--c
--c       output:
--c       m -- greatest integer less than or equal to l that divides n
--c
--        implicit none
--        integer n,l,m
--c
--c
--        m = l
--c
-- 1000   continue
--        if(m*(n/m) .eq. n) goto 2000
--c
--          m = m-1
--          goto 1000
--c
-- 2000   continue
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_sffti(l,ind,n,wsave)
--c
--c       initializes wsave for using routine idd_sfft.
--c
--c       input:
--c       l -- number of pairs of entries in the output of idd_sfft
--c            to compute
--c       ind -- indices of the pairs of entries in the output
--c              of idd_sfft to compute; the indices must be chosen
--c              in the range from 1 to n/2
--c       n -- length of the vector to be transformed
--c
--c       output:
--c       wsave -- array needed by routine idd_sfft for processing
--c                (the present routine does not use the last n elements
--c                 of wsave, but routine idd_sfft does)
--c
--        implicit none
--        integer l,ind(l),n
--        complex*16 wsave(2*l+15+4*n)
--c
--c
--        if(l .eq. 1) call idd_sffti1(ind,n,wsave)
--        if(l .gt. 1) call idd_sffti2(l,ind,n,wsave)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_sffti1(ind,n,wsave)
--c
--c       routine idd_sffti serves as a wrapper around
--c       the present routine; please see routine idd_sffti
--c       for documentation.
--c
--        implicit none
--        integer ind,n,k
--        real*8 r1,twopi,wsave(2*(2+15+4*n)),fact
--c
--        r1 = 1
--        twopi = 2*4*atan(r1)
--c
--c
--        fact = 1/sqrt(r1*n)
--c
--c
--        do k = 1,n
--          wsave(k) = cos(twopi*(k-1)*ind/(r1*n))*fact
--        enddo ! k
--c
--        do k = 1,n
--          wsave(n+k) = -sin(twopi*(k-1)*ind/(r1*n))*fact
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_sffti2(l,ind,n,wsave)
--c
--c       routine idd_sffti serves as a wrapper around
--c       the present routine; please see routine idd_sffti
--c       for documentation.
--c
--        implicit none
--        integer l,ind(l),n,nblock,ii,m,idivm,imodm,i,j,k
--        real*8 r1,twopi,fact
--        complex*16 wsave(2*l+15+4*n),ci,twopii
--c
--        ci = (0,1)
--        r1 = 1
--        twopi = 2*4*atan(r1)
--        twopii = twopi*ci
--c
--c
--c       Determine the block lengths for the FFTs.
--c
--        call idd_ldiv(l,n,nblock)
--        m = n/nblock
--c
--c
--c       Initialize wsave for using routine dfftf.
--c
--        call dffti(nblock,wsave)
--c
--c
--c       Calculate the coefficients in the linear combinations
--c       needed for the direct portion of the calculation.
--c
--        fact = 1/sqrt(r1*n)
--c
--        ii = 2*l+15
--c
--        do j = 1,l
--c
--c
--          i = ind(j)
--c
--c
--          if(i .le. n/2-m/2) then
--c
--            idivm = (i-1)/m
--            imodm = (i-1)-m*idivm
--c
--            do k = 1,m
--              wsave(ii+m*(j-1)+k) = exp(-twopii*(k-1)*imodm/(r1*m))
--     1         * exp(-twopii*(k-1)*(idivm+1)/(r1*n)) * fact
--            enddo ! k
--c
--          endif ! i .le. n/2-m/2
--c
--c
--          if(i .gt. n/2-m/2) then
--c
--            idivm = i/(m/2)
--            imodm = i-(m/2)*idivm
--c
--            do k = 1,m
--              wsave(ii+m*(j-1)+k) = exp(-twopii*(k-1)*imodm/(r1*m))
--     1                            * fact
--            enddo ! k
--c
--          endif ! i .gt. n/2-m/2
--c
--c
--        enddo ! j
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_sfft(l,ind,n,wsave,v)
--c
--c       computes a subset of the entries of the DFT of v,
--c       composed with permutation matrices both on input and on output,
--c       via a two-stage procedure (debugging code routine dfftf2 above
--c       is supposed to calculate the full vector from which idd_sfft
--c       returns a subset of the entries, when dfftf2 has
--c       the same parameter nblock as in the present routine).
--c
--c       input:
--c       l -- number of pairs of entries in the output to compute
--c       ind -- indices of the pairs of entries in the output
--c              to compute; the indices must be chosen
--c              in the range from 1 to n/2
--c       n -- length of v; n must be a positive integer power of 2
--c       v -- vector to be transformed
--c       wsave -- processing array initialized by routine idd_sffti
--c
--c       output:
--c       v -- pairs of entries indexed by ind are given
--c            their appropriately transformed values
--c
--c       _N.B._: n must be a positive integer power of 2.
--c
--c       references:
--c       Sorensen and Burrus, "Efficient computation of the DFT with
--c            only a subset of input or output points,"
--c            IEEE Transactions on Signal Processing, 41 (3): 1184-1200,
--c            1993.
--c       Woolfe, Liberty, Rokhlin, Tygert, "A fast randomized algorithm
--c            for the approximation of matrices," Applied and
--c            Computational Harmonic Analysis, 25 (3): 335-366, 2008;
--c            Section 3.3.
--c
--        implicit none
--        integer l,ind(l),n
--        real*8 v(n)
--        complex*16 wsave(2*l+15+4*n)
--c
--c
--        if(l .eq. 1) call idd_sfft1(ind,n,v,wsave)
--        if(l .gt. 1) call idd_sfft2(l,ind,n,v,wsave)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_sfft1(ind,n,v,wsave)
--c
--c       routine idd_sfft serves as a wrapper around
--c       the present routine; please see routine idd_sfft
--c       for documentation.
--c
--        implicit none
--        integer ind,n,k
--        real*8 v(n),r1,twopi,sumr,sumi,fact,wsave(2*(2+15+4*n))
--c
--        r1 = 1
--        twopi = 2*4*atan(r1)
--c
--c
--        if(ind .lt. n/2) then
--c
--c
--          sumr = 0
--c
--          do k = 1,n
--            sumr = sumr+wsave(k)*v(k)
--          enddo ! k
--c
--c
--          sumi = 0
--c
--          do k = 1,n
--            sumi = sumi+wsave(n+k)*v(k)
--          enddo ! k
--c
--c
--        endif ! ind .lt. n/2
--c
--c
--        if(ind .eq. n/2) then
--c
--c
--          fact = 1/sqrt(r1*n)
--c
--c
--          sumr = 0
--c
--          do k = 1,n
--            sumr = sumr+v(k)
--          enddo ! k
--c
--          sumr = sumr*fact
--c
--c
--          sumi = 0
--c
--          do k = 1,n/2
--            sumi = sumi+v(2*k-1)
--            sumi = sumi-v(2*k)
--          enddo ! k
--c
--          sumi = sumi*fact
--c
--c
--        endif ! ind .eq. n/2
--c
--c
--        v(2*ind-1) = sumr
--        v(2*ind) = sumi
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_sfft2(l,ind,n,v,wsave)
--c
--c       routine idd_sfft serves as a wrapper around
--c       the present routine; please see routine idd_sfft
--c       for documentation.
--c
--        implicit none
--        integer n,m,l,k,j,ind(l),i,idivm,nblock,ii,iii,imodm
--        real*8 r1,twopi,v(n),rsum,fact
--        complex*16 wsave(2*l+15+4*n),ci,sum
--c
--        ci = (0,1)
--        r1 = 1
--        twopi = 2*4*atan(r1)
--c
--c
--c       Determine the block lengths for the FFTs.
--c
--        call idd_ldiv(l,n,nblock)
--c
--c
--        m = n/nblock
--c
--c
--c       FFT each block of length nblock of v.
--c
--        do k = 1,m
--          call dfftf(nblock,v(nblock*(k-1)+1),wsave)
--        enddo ! k
--c
--c
--c       Transpose v to obtain wsave(2*l+15+2*n+1 : 2*l+15+3*n).
--c
--        iii = 2*l+15+2*n
--c
--        do k = 1,m
--          do j = 1,nblock/2-1
--            wsave(iii+m*(j-1)+k) = v(nblock*(k-1)+2*j)
--     1                           + ci*v(nblock*(k-1)+2*j+1)
--          enddo ! j
--        enddo ! k
--c
--c       Handle the purely real frequency components separately.
--c
--        do k = 1,m
--          wsave(iii+m*(nblock/2-1)+k) = v(nblock*(k-1)+nblock)
--          wsave(iii+m*(nblock/2)+k) = v(nblock*(k-1)+1)
--        enddo ! k
--c
--c
--c       Directly calculate the desired entries of v.
--c
--        ii = 2*l+15
--c
--        do j = 1,l
--c
--c
--          i = ind(j)
--c
--c
--          if(i .le. n/2-m/2) then
--c
--            idivm = (i-1)/m
--            imodm = (i-1)-m*idivm
--c
--            sum = 0
--c
--            do k = 1,m
--              sum = sum + wsave(iii+m*idivm+k) * wsave(ii+m*(j-1)+k)
--            enddo ! k
--c
--            v(2*i-1) = sum
--            v(2*i) = -ci*sum
--c
--          endif ! i .le. n/2-m/2
--c
--c
--          if(i .gt. n/2-m/2) then
--c
--            if(i .lt. n/2) then
--c
--              idivm = i/(m/2)
--              imodm = i-(m/2)*idivm
--c
--              sum = 0
--c
--              do k = 1,m
--                sum = sum + wsave(iii+m*(nblock/2)+k)
--     1              * wsave(ii+m*(j-1)+k)
--              enddo ! k
--c
--              v(2*i-1) = sum
--              v(2*i) = -ci*sum
--c
--            endif
--c
--            if(i .eq. n/2) then
--c
--              fact = 1/sqrt(r1*n)
--c
--c
--              rsum = 0
--c
--              do k = 1,m
--                rsum = rsum + wsave(iii+m*(nblock/2)+k)
--              enddo ! k
--c
--              v(n-1) = rsum*fact
--c
--c
--              rsum = 0
--c
--              do k = 1,m/2
--                rsum = rsum + wsave(iii+m*(nblock/2)+2*k-1)
--                rsum = rsum - wsave(iii+m*(nblock/2)+2*k)
--              enddo ! k
--c
--              v(n) = rsum*fact
--c
--            endif
--c
--          endif ! i .gt. n/2-m/2
--c
--c
--        enddo ! j
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idd_snorm.f b/scipy/linalg/src/id_dist/src/idd_snorm.f
-deleted file mode 100644
-index c718ce12f..000000000
---- a/scipy/linalg/src/id_dist/src/idd_snorm.f
-+++ /dev/null
-@@ -1,400 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idd_snorm estimates the spectral norm
--c       of a matrix specified by routines for applying the matrix
--c       and its transpose to arbitrary vectors. This routine uses
--c       the power method with a random starting vector.
--c
--c       routine idd_diffsnorm estimates the spectral norm
--c       of the difference between two matrices specified by routines
--c       for applying the matrices and their transposes
--c       to arbitrary vectors. This routine uses
--c       the power method with a random starting vector.
--c
--c       routine idd_enorm calculates the Euclidean norm of a vector.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idd_snorm(m,n,matvect,p1t,p2t,p3t,p4t,
--     1                       matvec,p1,p2,p3,p4,its,snorm,v,u)
--c
--c       estimates the spectral norm of a matrix a specified
--c       by a routine matvec for applying a to an arbitrary vector,
--c       and by a routine matvect for applying a^T
--c       to an arbitrary vector. This routine uses the power method
--c       with a random starting vector.
--c
--c       input:
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       matvect -- routine which applies the transpose of a
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matvect(m,x,n,y,p1t,p2t,p3t,p4t),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the transpose of a
--c                  is to be applied,
--c                  n is the length of y,
--c                  y is the product of the transpose of a and x,
--c                  and p1t, p2t, p3t, and p4t are user-specified
--c                  parameters
--c       p1t -- parameter to be passed to routine matvect
--c       p2t -- parameter to be passed to routine matvect
--c       p3t -- parameter to be passed to routine matvect
--c       p4t -- parameter to be passed to routine matvect
--c       matvec -- routine which applies the matrix a
--c                 to an arbitrary vector; this routine must have
--c                 a calling sequence of the form
--c
--c                 matvec(n,x,m,y,p1,p2,p3,p4),
--c
--c                 where n is the length of x,
--c                 x is the vector to which a is to be applied,
--c                 m is the length of y,
--c                 y is the product of a and x,
--c                 and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvec
--c       p2 -- parameter to be passed to routine matvec
--c       p3 -- parameter to be passed to routine matvec
--c       p4 -- parameter to be passed to routine matvec
--c       its -- number of iterations of the power method to conduct
--c
--c       output:
--c       snorm -- estimate of the spectral norm of a
--c       v -- estimate of a normalized right singular vector
--c            corresponding to the greatest singular value of a
--c
--c       work:
--c       u -- must be at least m real*8 elements long
--c
--c       reference:
--c       Kuczynski and Wozniakowski, "Estimating the largest eigenvalue
--c            by the power and Lanczos algorithms with a random start,"
--c            SIAM Journal on Matrix Analysis and Applications,
--c            13 (4): 1992, 1094-1122.
--c
--        implicit none
--        integer m,n,its,it,k
--        real*8 snorm,enorm,p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m),v(n)
--        external matvect,matvec
--c
--c
--c       Fill the real and imaginary parts of each entry
--c       of the initial vector v with i.i.d. random variables
--c       drawn uniformly from [-1,1].
--c
--        call id_srand(n,v)
--c
--        do k = 1,n
--          v(k) = 2*v(k)-1
--        enddo ! k
--c
--c
--c       Normalize v.
--c
--        call idd_enorm(n,v,enorm)
--c
--        do k = 1,n
--          v(k) = v(k)/enorm
--        enddo ! k
--c
--c
--        do it = 1,its
--c
--c         Apply a to v, obtaining u.
--c
--          call matvec(n,v,m,u,p1,p2,p3,p4)
--c
--c         Apply a^T to u, obtaining v.
--c
--          call matvect(m,u,n,v,p1t,p2t,p3t,p4t)
--c
--c         Normalize v.
--c
--          call idd_enorm(n,v,snorm)
--c
--          if(snorm .gt. 0) then
--c
--            do k = 1,n
--              v(k) = v(k)/snorm
--            enddo ! k
--c
--          endif
--c
--          snorm = sqrt(snorm)
--c
--        enddo ! it
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_enorm(n,v,enorm)
--c
--c       computes the Euclidean norm of v, the square root
--c       of the sum of the squares of the entries of v.
--c
--c       input:
--c       n -- length of v
--c       v -- vector whose Euclidean norm is to be calculated
--c
--c       output:
--c       enorm -- Euclidean norm of v
--c
--        implicit none
--        integer n,k
--        real*8 enorm,v(n)
--c
--c
--        enorm = 0
--c
--        do k = 1,n
--          enorm = enorm+v(k)**2
--        enddo ! k
--c
--        enorm = sqrt(enorm)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_diffsnorm(m,n,matvect,p1t,p2t,p3t,p4t,
--     1                           matvect2,p1t2,p2t2,p3t2,p4t2,
--     2                           matvec,p1,p2,p3,p4,
--     3                           matvec2,p12,p22,p32,p42,its,snorm,w)
--c
--c       estimates the spectral norm of the difference between matrices
--c       a and a2, where a is specified by routines matvec and matvect
--c       for applying a and a^T to arbitrary vectors,
--c       and a2 is specified by routines matvec2 and matvect2
--c       for applying a2 and (a2)^T to arbitrary vectors.
--c       This routine uses the power method
--c       with a random starting vector.
--c
--c       input:
--c       m -- number of rows in a, as well as the number of rows in a2
--c       n -- number of columns in a, as well as the number of columns
--c            in a2
--c       matvect -- routine which applies the transpose of a
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matvect(m,x,n,y,p1t,p2t,p3t,p4t),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the transpose of a
--c                  is to be applied,
--c                  n is the length of y,
--c                  y is the product of the transpose of a and x,
--c                  and p1t, p2t, p3t, and p4t are user-specified
--c                  parameters
--c       p1t -- parameter to be passed to routine matvect
--c       p2t -- parameter to be passed to routine matvect
--c       p3t -- parameter to be passed to routine matvect
--c       p4t -- parameter to be passed to routine matvect
--c       matvect2 -- routine which applies the transpose of a2
--c                   to an arbitrary vector; this routine must have
--c                   a calling sequence of the form
--c
--c                   matvect2(m,x,n,y,p1t2,p2t2,p3t2,p4t2),
--c
--c                   where m is the length of x,
--c                   x is the vector to which the transpose of a2
--c                   is to be applied,
--c                   n is the length of y,
--c                   y is the product of the transpose of a2 and x,
--c                   and p1t2, p2t2, p3t2, and p4t2 are user-specified
--c                   parameters
--c       p1t2 -- parameter to be passed to routine matvect2
--c       p2t2 -- parameter to be passed to routine matvect2
--c       p3t2 -- parameter to be passed to routine matvect2
--c       p4t2 -- parameter to be passed to routine matvect2
--c       matvec -- routine which applies the matrix a
--c                 to an arbitrary vector; this routine must have
--c                 a calling sequence of the form
--c
--c                 matvec(n,x,m,y,p1,p2,p3,p4),
--c
--c                 where n is the length of x,
--c                 x is the vector to which a is to be applied,
--c                 m is the length of y,
--c                 y is the product of a and x,
--c                 and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvec
--c       p2 -- parameter to be passed to routine matvec
--c       p3 -- parameter to be passed to routine matvec
--c       p4 -- parameter to be passed to routine matvec
--c       matvec2 -- routine which applies the matrix a2
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matvec2(n,x,m,y,p12,p22,p32,p42),
--c
--c                  where n is the length of x,
--c                  x is the vector to which a2 is to be applied,
--c                  m is the length of y,
--c                  y is the product of a2 and x, and
--c                  p12, p22, p32, and p42 are user-specified parameters
--c       p12 -- parameter to be passed to routine matvec2
--c       p22 -- parameter to be passed to routine matvec2
--c       p32 -- parameter to be passed to routine matvec2
--c       p42 -- parameter to be passed to routine matvec2
--c       its -- number of iterations of the power method to conduct
--c
--c       output:
--c       snorm -- estimate of the spectral norm of a-a2
--c
--c       work:
--c       w -- must be at least 3*m+3*n real*8 elements long
--c
--c       reference:
--c       Kuczynski and Wozniakowski, "Estimating the largest eigenvalue
--c            by the power and Lanczos algorithms with a random start,"
--c            SIAM Journal on Matrix Analysis and Applications,
--c            13 (4): 1992, 1094-1122.
--c
--        implicit none
--        integer m,n,its,lw,iu,lu,iu1,lu1,iu2,lu2,
--     1          iv,lv,iv1,lv1,iv2,lv2
--        real*8 snorm,p1t,p2t,p3t,p4t,p1t2,p2t2,p3t2,p4t2,
--     1         p1,p2,p3,p4,p12,p22,p32,p42,w(3*m+3*n)
--        external matvect,matvec,matvect2,matvec2
--c
--c
--c       Allocate memory in w.
--c
--        lw = 0
--c
--        iu = lw+1
--        lu = m
--        lw = lw+lu
--c
--        iu1 = lw+1
--        lu1 = m
--        lw = lw+lu1
--c
--        iu2 = lw+1
--        lu2 = m
--        lw = lw+lu2
--c
--        iv = lw+1
--        lv = n
--        lw = lw+1
--c
--        iv1 = lw+1
--        lv1 = n
--        lw = lw+lv1
--c
--        iv2 = lw+1
--        lv2 = n
--        lw = lw+lv2
--c
--c
--        call idd_diffsnorm0(m,n,matvect,p1t,p2t,p3t,p4t,
--     1                      matvect2,p1t2,p2t2,p3t2,p4t2,
--     2                      matvec,p1,p2,p3,p4,
--     3                      matvec2,p12,p22,p32,p42,
--     4                      its,snorm,w(iu),w(iu1),w(iu2),
--     5                      w(iv),w(iv1),w(iv2))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_diffsnorm0(m,n,matvect,p1t,p2t,p3t,p4t,
--     1                            matvect2,p1t2,p2t2,p3t2,p4t2,
--     2                            matvec,p1,p2,p3,p4,
--     3                            matvec2,p12,p22,p32,p42,
--     4                            its,snorm,u,u1,u2,v,v1,v2)
--c
--c       routine idd_diffsnorm serves as a memory wrapper
--c       for the present routine. (Please see routine idd_diffsnorm
--c       for further documentation.)
--c
--        implicit none
--        integer m,n,its,it,k
--        real*8 snorm,enorm,p1t,p2t,p3t,p4t,p1t2,p2t2,p3t2,p4t2,
--     1         p1,p2,p3,p4,p12,p22,p32,p42,u(m),u1(m),u2(m),
--     2         v(n),v1(n),v2(n)
--        external matvect,matvec,matvect2,matvec2
--c
--c
--c       Fill the real and imaginary parts of each entry
--c       of the initial vector v with i.i.d. random variables
--c       drawn uniformly from [-1,1].
--c
--        call id_srand(n,v)
--c
--        do k = 1,n
--          v(k) = 2*v(k)-1
--        enddo ! k
--c
--c
--c       Normalize v.
--c
--        call idd_enorm(n,v,enorm)
--c
--        do k = 1,n
--          v(k) = v(k)/enorm
--        enddo ! k
--c
--c
--        do it = 1,its
--c
--c         Apply a and a2 to v, obtaining u1 and u2.
--c
--          call matvec(n,v,m,u1,p1,p2,p3,p4)
--          call matvec2(n,v,m,u2,p12,p22,p32,p42)
--c
--c         Form u = u1-u2.
--c
--          do k = 1,m
--            u(k) = u1(k)-u2(k)
--          enddo ! k
--c
--c         Apply a^T and (a2)^T to u, obtaining v1 and v2.
--c
--          call matvect(m,u,n,v1,p1t,p2t,p3t,p4t)
--          call matvect2(m,u,n,v2,p1t2,p2t2,p3t2,p4t2)
--c
--c         Form v = v1-v2.
--c
--          do k = 1,n
--            v(k) = v1(k)-v2(k)
--          enddo ! k
--c
--c         Normalize v.
--c
--          call idd_enorm(n,v,snorm)
--c
--          if(snorm .gt. 0) then
--c
--            do k = 1,n
--              v(k) = v(k)/snorm
--            enddo ! k
--c
--          endif
--c
--          snorm = sqrt(snorm)
--c
--        enddo ! it
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idd_svd.f b/scipy/linalg/src/id_dist/src/idd_svd.f
-deleted file mode 100644
-index 969422b8c..000000000
---- a/scipy/linalg/src/id_dist/src/idd_svd.f
-+++ /dev/null
-@@ -1,409 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddr_svd computes an approximation of specified rank
--c       to a given matrix, in the usual SVD form U S V^T,
--c       where U has orthonormal columns, V has orthonormal columns,
--c       and S is diagonal.
--c
--c       routine iddp_svd computes an approximation of specified
--c       precision to a given matrix, in the usual SVD form U S V^T,
--c       where U has orthonormal columns, V has orthonormal columns,
--c       and S is diagonal.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine iddr_svd(m,n,a,krank,u,v,s,ier,r)
--c
--c       constructs a rank-krank SVD  u diag(s) v^T  approximating a,
--c       where u is an m x krank matrix whose columns are orthonormal,
--c       v is an n x krank matrix whose columns are orthonormal,
--c       and diag(s) is a diagonal krank x krank matrix whose entries
--c       are all nonnegative. This routine combines a QR code
--c       (which is based on plane/Householder reflections)
--c       with the LAPACK routine dgesdd.
--c
--c       input:
--c       m -- first dimension of a and u
--c       n -- second dimension of a, and first dimension of v
--c       a -- matrix to be SVD'd
--c       krank -- desired rank of the approximation to a
--c
--c       output:
--c       u -- left singular vectors of a corresponding
--c            to the k greatest singular values of a
--c       v -- right singular vectors of a corresponding
--c            to the k greatest singular values of a
--c       s -- k greatest singular values of a
--c       ier -- 0 when the routine terminates successfully;
--c              nonzero when the routine encounters an error
--c
--c       work:
--c       r -- must be at least
--c            (krank+2)*n+8*min(m,n)+15*krank**2+8*krank
--c            real*8 elements long
--c
--c       _N.B._: This routine destroys a. Also, please beware that
--c               the source code for this routine could be clearer.
--c
--        implicit none
--        character*1 jobz
--        integer m,n,k,krank,iftranspose,ldr,ldu,ldvt,lwork,
--     1          info,j,ier,io
--        real*8 a(m,n),u(m,krank),v(n*krank),s(krank),r(*)
--c
--c
--        io = 8*min(m,n)
--c
--c
--        ier = 0
--c
--c
--c       Compute a pivoted QR decomposition of a.
--c
--        call iddr_qrpiv(m,n,a,krank,r,r(io+1))
--c
--c
--c       Extract R from the QR decomposition.
--c
--        call idd_retriever(m,n,a,krank,r(io+1))
--c
--c
--c       Rearrange R according to ind (which is stored in r).
--c
--        call idd_permuter(krank,r,krank,n,r(io+1))
--c
--c
--c       Use LAPACK to SVD R,
--c       storing the krank (krank x 1) left singular vectors
--c       in r(io+krank*n+1 : io+krank*n+krank*krank).
--c
--        jobz = 'S'
--        ldr = krank
--        lwork = 2*(3*krank**2+n+4*krank**2+4*krank)
--        ldu = krank
--        ldvt = krank
--c
--        call dgesdd(jobz,krank,n,r(io+1),ldr,s,r(io+krank*n+1),ldu,
--     1              v,ldvt,r(io+krank*n+krank*krank+1),lwork,r,info)
--c
--        if(info .ne. 0) then
--          ier = info
--          return
--        endif
--c
--c
--c       Multiply the U from R from the left by Q to obtain the U
--c       for A.
--c
--        do k = 1,krank
--c
--          do j = 1,krank
--            u(j,k) = r(io+krank*n+j+krank*(k-1))
--          enddo ! j
--c
--          do j = krank+1,m
--            u(j,k) = 0
--          enddo ! j
--c
--        enddo ! k
--c
--        iftranspose = 0
--        call idd_qmatmat(iftranspose,m,n,a,krank,krank,u,r)
--c
--c
--c       Transpose v to obtain r.
--c
--        call idd_transer(krank,n,v,r)
--c
--c
--c       Copy r into v.
--c
--        do k = 1,n*krank
--          v(k) = r(k)
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddp_svd(lw,eps,m,n,a,krank,iu,iv,is,w,ier)
--c
--c       constructs a rank-krank SVD  U Sigma V^T  approximating a
--c       to precision eps, where U is an m x krank matrix whose
--c       columns are orthonormal, V is an n x krank matrix whose
--c       columns are orthonormal, and Sigma is a diagonal krank x krank
--c       matrix whose entries are all nonnegative.
--c       The entries of U are stored in w, starting at w(iu);
--c       the entries of V are stored in w, starting at w(iv).
--c       The diagonal entries of Sigma are stored in w,
--c       starting at w(is). This routine combines a QR code
--c       (which is based on plane/Householder reflections)
--c       with the LAPACK routine dgesdd.
--c
--c       input:
--c       lw -- maximum usable length of w (in real*8 elements)
--c       eps -- precision to which the SVD approximates a
--c       m -- first dimension of a and u
--c       n -- second dimension of a, and first dimension of v
--c       a -- matrix to be SVD'd
--c
--c       output:
--c       krank -- rank of the approximation to a
--c       iu -- index in w of the first entry of the matrix
--c             of orthonormal left singular vectors of a
--c       iv -- index in w of the first entry of the matrix
--c             of orthonormal right singular vectors of a
--c       is -- index in w of the first entry of the array
--c             of singular values of a
--c       w -- array containing the singular values and singular vectors
--c            of a; w doubles as a work array, and so must be at least
--c            (krank+1)*(m+2*n+9)+8*min(m,n)+15*krank**2
--c            real*8 elements long, where krank is the rank
--c            output by the present routine
--c       ier -- 0 when the routine terminates successfully;
--c              -1000 when lw is too small;
--c              other nonzero values when dgesdd bombs
--c
--c       _N.B._: This routine destroys a. Also, please beware that
--c               the source code for this routine could be clearer.
--c               w must be at least
--c               (krank+1)*(m+2*n+9)+8*min(m,n)+15*krank**2
--c               real*8 elements long, where krank is the rank
--c               output by the present routine.
--c
--        implicit none
--        character*1 jobz
--        integer m,n,k,krank,iftranspose,ldr,ldu,ldvt,lwork,
--     1          info,j,ier,io,iu,iv,is,ivi,isi,lw,lu,lv,ls
--        real*8 a(m,n),w(*),eps
--c
--c
--        io = 8*min(m,n)
--c
--c
--        ier = 0
--c
--c
--c       Compute a pivoted QR decomposition of a.
--c
--        call iddp_qrpiv(eps,m,n,a,krank,w,w(io+1))
--c
--c
--        if(krank .gt. 0) then
--c
--c
--c         Extract R from the QR decomposition.
--c
--          call idd_retriever(m,n,a,krank,w(io+1))
--c
--c
--c         Rearrange R according to ind (which is stored in w).
--c
--          call idd_permuter(krank,w,krank,n,w(io+1))
--c
--c
--c         Use LAPACK to SVD R,
--c         storing the krank (krank x 1) left singular vectors
--c         in w(io+krank*n+1 : io+krank*n+krank*krank).
--c
--          jobz = 'S'
--          ldr = krank
--          lwork = 2*(3*krank**2+n+4*krank**2+4*krank)
--          ldu = krank
--          ldvt = krank
--c
--          ivi = io+krank*n+krank*krank+lwork+1
--          lv = n*krank
--c
--          isi = ivi+lv
--          ls = krank
--c
--          if(lw .lt. isi+ls+m*krank-1) then
--            ier = -1000
--            return
--          endif
--c
--          call dgesdd(jobz,krank,n,w(io+1),ldr,w(isi),w(io+krank*n+1),
--     1                ldu,w(ivi),ldvt,w(io+krank*n+krank*krank+1),
--     2                lwork,w,info)
--c
--          if(info .ne. 0) then
--            ier = info
--            return
--          endif
--c
--c
--c         Transpose w(ivi:ivi+lv-1) to obtain V.
--c
--          iv = 1
--          call idd_transer(krank,n,w(ivi),w(iv))
--c
--c
--c         Copy w(isi:isi+ls-1) into w(is:is+ls-1).
--c
--          is = iv+lv
--c
--          do k = 1,ls
--            w(is+k-1) = w(isi+k-1)
--          enddo ! k
--c
--c
--c         Multiply the U from R from the left by Q to obtain the U
--c         for A.
--c
--          iu = is+ls
--          lu = m*krank
--c
--          do k = 1,krank
--c
--            do j = 1,krank
--              w(iu-1+j+krank*(k-1)) = w(io+krank*n+j+krank*(k-1))
--            enddo ! j
--c
--          enddo ! k
--c
--          do k = krank,1,-1
--c
--            do j = m,krank+1,-1
--              w(iu-1+j+m*(k-1)) = 0
--            enddo ! j
--c
--            do j = krank,1,-1
--              w(iu-1+j+m*(k-1)) = w(iu-1+j+krank*(k-1))
--            enddo ! j
--c
--          enddo ! k
--c
--          iftranspose = 0
--          call idd_qmatmat(iftranspose,m,n,a,krank,krank,w(iu),
--     1                     w(iu+lu+1))
--c
--c
--        endif ! krank .gt. 0
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_permuter(krank,ind,m,n,a)
--c
--c       permutes the columns of a according to ind obtained
--c       from routine iddr_qrpiv or iddp_qrpiv, assuming that
--c       a = q r from iddr_qrpiv or iddp_qrpiv.
--c
--c       input:
--c       krank -- rank specified to routine iddr_qrpiv
--c                or obtained from routine iddp_qrpiv
--c       ind -- indexing array obtained from routine iddr_qrpiv
--c              or iddp_qrpiv
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       a -- matrix to be rearranged
--c
--c       output:
--c       a -- rearranged matrix
--c
--        implicit none
--        integer k,krank,m,n,j,ind(krank)
--        real*8 rswap,a(m,n)
--c
--c
--        do k = krank,1,-1
--          do j = 1,m
--c
--            rswap = a(j,k)
--            a(j,k) = a(j,ind(k))
--            a(j,ind(k)) = rswap
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_retriever(m,n,a,krank,r)
--c
--c       extracts R in the QR decomposition specified by the output a
--c       of the routine iddr_qrpiv or iddp_qrpiv
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a and r
--c       a -- output of routine iddr_qrpiv or iddp_qrpiv
--c       krank -- rank specified to routine iddr_qrpiv,
--c                or output by routine iddp_qrpiv
--c
--c       output:
--c       r -- triangular factor in the QR decomposition specified
--c            by the output a of the routine iddr_qrpiv or iddp_qrpiv
--c
--        implicit none
--        integer m,n,j,k,krank
--        real*8 a(m,n),r(krank,n)
--c
--c
--c       Copy a into r and zero out the appropriate
--c       Householder vectors that are stored in one triangle of a.
--c
--        do k = 1,n
--          do j = 1,krank
--            r(j,k) = a(j,k)
--          enddo ! j
--        enddo ! k
--c
--        do k = 1,n
--          if(k .lt. krank) then
--            do j = k+1,krank
--              r(j,k) = 0
--            enddo ! j
--          endif
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_transer(m,n,a,at)
--c
--c       forms the transpose at of a.
--c
--c       input:
--c       m -- first dimension of a and second dimension of at
--c       n -- second dimension of a and first dimension of at
--c       a -- matrix to be transposed
--c
--c       output:
--c       at -- transpose of a
--c
--        implicit none
--        integer m,n,j,k
--        real*8 a(m,n),at(n,m)
--c
--c
--        do k = 1,n
--          do j = 1,m
--            at(k,j) = a(j,k)
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/iddp_aid.f b/scipy/linalg/src/id_dist/src/iddp_aid.f
-deleted file mode 100644
-index f3f9ddfdd..000000000
---- a/scipy/linalg/src/id_dist/src/iddp_aid.f
-+++ /dev/null
-@@ -1,386 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddp_aid computes the ID, to a specified precision,
--c       of an arbitrary matrix. This routine is randomized.
--c
--c       routine idd_estrank estimates the numerical rank,
--c       to a specified precision, of an arbitrary matrix.
--c       This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine iddp_aid(eps,m,n,a,work,krank,list,proj)
--c
--c       computes the ID of the matrix a, i.e., lists in list
--c       the indices of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                        krank
--c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
--c                         l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon dimensioned epsilon(m,n-krank)
--c       such that the greatest singular value of epsilon
--c       <= the greatest singular value of a * eps.
--c
--c       input:
--c       eps -- precision to which the ID is to be computed
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       a -- matrix to be decomposed; the present routine does not
--c            alter a
--c       work -- initialization array that has been constructed
--c               by routine idd_frmi
--c
--c       output:
--c       krank -- numerical rank of a to precision eps
--c       list -- indices of the columns in the ID
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns
--c               in the original matrix being ID'd;
--c               proj doubles as a work array in the present routine, so
--c               proj must be at least n*(2*n2+1)+n2+1 real*8 elements
--c               long, where n2 is the greatest integer less than
--c               or equal to m, such that n2 is a positive integer
--c               power of two.
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c               proj must be at least n*(2*n2+1)+n2+1 real*8 elements
--c               long, where n2 is the greatest integer less than
--c               or equal to m, such that n2 is a positive integer
--c               power of two.
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,n,list(n),krank,kranki,n2
--        real*8 eps,a(m,n),proj(*),work(17*m+70)
--c
--c
--c       Allocate memory in proj.
--c
--        n2 = work(2)
--c
--c
--c       Find the rank of a.
--c
--        call idd_estrank(eps,m,n,a,work,kranki,proj)
--c
--c
--        if(kranki .eq. 0) call iddp_aid0(eps,m,n,a,krank,list,proj,
--     1                                   proj(m*n+1))
--c
--        if(kranki .ne. 0) call iddp_aid1(eps,n2,n,kranki,proj,
--     1                                   krank,list,proj(n2*n+1))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddp_aid0(eps,m,n,a,krank,list,proj,rnorms)
--c
--c       uses routine iddp_id to ID a without modifying its entries
--c       (in contrast to the usual behavior of iddp_id).
--c
--c       input:
--c       eps -- precision of the decomposition to be constructed
--c       m -- first dimension of a
--c       n -- second dimension of a
--c
--c       output:
--c       krank -- numerical rank of the ID
--c       list -- indices of the columns in the ID
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns in a;
--c               proj doubles as a work array in the present routine, so
--c               must be at least m*n real*8 elements long
--c
--c       work:
--c       rnorms -- must be at least n real*8 elements long
--c
--c       _N.B._: proj must be at least m*n real*8 elements long
--c
--        implicit none
--        integer m,n,krank,list(n),j,k
--        real*8 eps,a(m,n),proj(m,n),rnorms(n)
--c
--c
--c       Copy a into proj.
--c
--        do k = 1,n
--          do j = 1,m
--            proj(j,k) = a(j,k)
--          enddo ! j
--        enddo ! k
--c
--c
--c       ID proj.
--c
--        call iddp_id(eps,m,n,proj,krank,list,rnorms)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddp_aid1(eps,n2,n,kranki,proj,krank,list,rnorms)
--c
--c       IDs the uppermost kranki x n block of the n2 x n matrix
--c       input as proj.
--c
--c       input:
--c       eps -- precision of the decomposition to be constructed
--c       n2 -- first dimension of proj as input
--c       n -- second dimension of proj as input
--c       kranki -- number of rows to extract from proj
--c       proj -- matrix containing the kranki x n block to be ID'd
--c
--c       output:
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns
--c               in the original matrix being ID'd
--c       krank -- numerical rank of the ID
--c       list -- indices of the columns in the ID
--c
--c       work:
--c       rnorms -- must be at least n real*8 elements long
--c
--        implicit none
--        integer n,n2,kranki,krank,list(n),j,k
--        real*8 eps,proj(n2*n),rnorms(n)
--c
--c
--c       Move the uppermost kranki x n block of the n2 x n matrix proj
--c       to the beginning of proj.
--c
--        do k = 1,n
--          do j = 1,kranki
--            proj(j+kranki*(k-1)) = proj(j+n2*(k-1))
--          enddo ! j
--        enddo ! k
--c
--c
--c       ID proj.
--c
--        call iddp_id(eps,kranki,n,proj,krank,list,rnorms)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_estrank(eps,m,n,a,w,krank,ra)
--c
--c       estimates the numerical rank krank of an m x n matrix a
--c       to precision eps. This routine applies n2 random vectors
--c       to a, obtaining ra, where n2 is the greatest integer
--c       less than or equal to m such that n2 is a positive integer
--c       power of two. krank is typically about 8 higher than
--c       the actual numerical rank.
--c
--c       input:
--c       eps -- precision defining the numerical rank
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       a -- matrix whose rank is to be estimated
--c       w -- initialization array that has been constructed
--c            by routine idd_frmi
--c
--c       output:
--c       krank -- estimate of the numerical rank of a;
--c                this routine returns krank = 0 when the actual
--c                numerical rank is nearly full (that is,
--c                greater than n - 8 or n2 - 8)
--c       ra -- product of an n2 x m random matrix and the m x n matrix
--c             a, where n2 is the greatest integer less than or equal
--c             to m such that n2 is a positive integer power of two;
--c             ra doubles as a work array in the present routine, and so
--c             must be at least n*n2+(n+1)*(n2+1) real*8 elements long
--c
--c       _N.B._: ra must be at least n*n2+(n2+1)*(n+1) real*8
--c               elements long for use in the present routine
--c               (here, n2 is the greatest integer less than or equal
--c               to m, such that n2 is a positive integer power of two).
--c               This routine returns krank = 0 when the actual
--c               numerical rank is nearly full.
--c
--        implicit none
--        integer m,n,krank,n2,irat,lrat,iscal,lscal,ira,lra,lra2
--        real*8 eps,a(m,n),ra(*),w(17*m+70)
--c
--c
--c       Extract from the array w initialized by routine idd_frmi
--c       the greatest integer less than or equal to m that is
--c       a positive integer power of two.
--c
--        n2 = w(2)
--c
--c
--c       Allocate memory in ra.
--c
--        lra = 0
--c
--        ira = lra+1
--        lra2 = n2*n
--        lra = lra+lra2
--c
--        irat = lra+1
--        lrat = n*(n2+1)
--        lra = lra+lrat
--c
--        iscal = lra+1
--        lscal = n2+1
--        lra = lra+lscal
--c
--        call idd_estrank0(eps,m,n,a,w,n2,krank,ra(ira),ra(irat),
--     1                    ra(iscal))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_estrank0(eps,m,n,a,w,n2,krank,ra,rat,scal)
--c
--c       routine idd_estrank serves as a memory wrapper
--c       for the present routine. (Please see routine idd_estrank
--c       for further documentation.)
--c
--        implicit none
--        integer m,n,n2,krank,ifrescal,k,nulls,j
--        real*8 a(m,n),ra(n2,n),scal(n2+1),eps,residual,
--     1         w(17*m+70),rat(n,n2+1),ss,ssmax
--c
--c
--c       Apply the random matrix to every column of a, obtaining ra.
--c
--        do k = 1,n
--          call idd_frm(m,n2,w,a(1,k),ra(1,k))
--        enddo ! k
--c
--c
--c       Compute the sum of squares of the entries in each column of ra
--c       and the maximum of all such sums.
--c
--        ssmax = 0
--c
--        do k = 1,n
--c
--          ss = 0
--          do j = 1,m
--            ss = ss+a(j,k)**2
--          enddo ! j
--c
--          if(ss .gt. ssmax) ssmax = ss
--c
--        enddo ! k
--c
--c
--c       Transpose ra to obtain rat.
--c
--        call idd_atransposer(n2,n,ra,rat)
--c
--c
--        krank = 0
--        nulls = 0
--c
--c
--c       Loop until nulls = 7, krank+nulls = n2, or krank+nulls = n.
--c
-- 1000   continue
--c
--c
--          if(krank .gt. 0) then
--c
--c           Apply the previous Householder transformations
--c           to rat(:,krank+1).
--c
--            ifrescal = 0
--c
--            do k = 1,krank
--              call idd_houseapp(n-k+1,rat(1,k),rat(k,krank+1),
--     1                          ifrescal,scal(k),rat(k,krank+1))
--            enddo ! k
--c
--          endif ! krank .gt. 0
--c
--c
--c         Compute the Householder vector associated
--c         with rat(krank+1:*,krank+1).
--c
--          call idd_house(n-krank,rat(krank+1,krank+1),
--     1                   residual,rat(1,krank+1),scal(krank+1))
--          residual = abs(residual)
--c
--c
--          krank = krank+1
--          if(residual .le. eps*sqrt(ssmax)) nulls = nulls+1
--c
--c
--        if(nulls .lt. 7 .and. krank+nulls .lt. n2
--     1   .and. krank+nulls .lt. n)
--     2   goto 1000
--c
--c
--        if(nulls .lt. 7) krank = 0
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_atransposer(m,n,a,at)
--c
--c       transposes a to obtain at.
--c
--c       input:
--c       m -- first dimension of a, and second dimension of at
--c       n -- second dimension of a, and first dimension of at
--c       a -- matrix to be transposed
--c
--c       output:
--c       at -- transpose of a
--c
--        implicit none
--        integer m,n,j,k
--        real*8 a(m,n),at(n,m)
--c
--c
--        do k = 1,n
--          do j = 1,m
--c
--            at(k,j) = a(j,k)
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/iddp_asvd.f b/scipy/linalg/src/id_dist/src/iddp_asvd.f
-deleted file mode 100644
-index a3dea4611..000000000
---- a/scipy/linalg/src/id_dist/src/iddp_asvd.f
-+++ /dev/null
-@@ -1,180 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddp_asvd computes the SVD, to a specified precision,
--c       of an arbitrary matrix. This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine iddp_asvd(lw,eps,m,n,a,winit,krank,iu,iv,is,w,ier)
--c
--c       constructs a rank-krank SVD  U Sigma V^T  approximating a
--c       to precision eps, where U is an m x krank matrix whose
--c       columns are orthonormal, V is an n x krank matrix whose
--c       columns are orthonormal, and Sigma is a diagonal krank x krank
--c       matrix whose entries are all nonnegative.
--c       The entries of U are stored in w, starting at w(iu);
--c       the entries of V are stored in w, starting at w(iv).
--c       The diagonal entries of Sigma are stored in w,
--c       starting at w(is). This routine uses a randomized algorithm.
--c
--c       input:
--c       lw -- maximum usable length (in real*8 elements)
--c             of the array w
--c       eps -- precision of the desired approximation
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       a -- matrix to be approximated; the present routine does not
--c            alter a
--c       winit -- initialization array that has been constructed
--c                by routine idd_frmi
--c
--c       output:
--c       krank -- rank of the SVD constructed
--c       iu -- index in w of the first entry of the matrix
--c             of orthonormal left singular vectors of a
--c       iv -- index in w of the first entry of the matrix
--c             of orthonormal right singular vectors of a
--c       is -- index in w of the first entry of the array
--c             of singular values of a
--c       w -- array containing the singular values and singular vectors
--c            of a; w doubles as a work array, and so must be at least
--c            max( (krank+1)*(3*m+5*n+1)+25*krank**2, (2*n+1)*(n2+1) )
--c            real*8 elements long, where n2 is the greatest integer
--c            less than or equal to m, such that n2 is
--c            a positive integer power of two; krank is the rank output
--c            by this routine
--c       ier -- 0 when the routine terminates successfully;
--c              -1000 when lw is too small;
--c              other nonzero values when idd_id2svd bombs
--c
--c       _N.B._: w must be at least
--c               max( (krank+1)*(3*m+5*n+1)+25*krank^2, (2*n+1)*(n2+1) )
--c               real*8 elements long, where n2 is the greatest integer
--c               less than or equal to m, such that n2 is
--c               a positive integer power of two;
--c               krank is the rank output by this routine.
--c               Also, the algorithm used by this routine is randomized.
--c
--        implicit none
--        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
--     1          iwork,lwork,k,ier,lw2,iu,iv,is,iui,ivi,isi,lu,lv,ls
--        real*8 eps,a(m,n),winit(17*m+70),w(*)
--c
--c
--c       Allocate memory in w.
--c
--        lw2 = 0
--c
--        ilist = lw2+1
--        llist = n
--        lw2 = lw2+llist
--c
--        iproj = lw2+1
--c
--c
--c       ID a.
--c
--        call iddp_aid(eps,m,n,a,winit,krank,w(ilist),w(iproj))
--c
--c
--        if(krank .gt. 0) then
--c
--c
--c         Allocate more memory in w.
--c
--          lproj = krank*(n-krank)
--          lw2 = lw2+lproj
--c
--          icol = lw2+1
--          lcol = m*krank
--          lw2 = lw2+lcol
--c
--          iui = lw2+1
--          lu = m*krank
--          lw2 = lw2+lu
--c
--          ivi = lw2+1
--          lv = n*krank
--          lw2 = lw2+lv
--c
--          isi = lw2+1
--          ls = krank
--          lw2 = lw2+ls
--c
--          iwork = lw2+1
--          lwork = (krank+1)*(m+3*n)+26*krank**2
--          lw2 = lw2+lwork
--c
--c
--          if(lw .lt. lw2) then
--            ier = -1000
--            return
--          endif
--c
--c
--          call iddp_asvd0(m,n,a,krank,w(ilist),w(iproj),
--     1                    w(iui),w(ivi),w(isi),ier,w(icol),w(iwork))
--          if(ier .ne. 0) return
--c
--c
--          iu = 1
--          iv = iu+lu
--          is = iv+lv
--c
--c
--c         Copy the singular values and singular vectors
--c         into their proper locations.
--c
--          do k = 1,lu
--            w(iu+k-1) = w(iui+k-1)
--          enddo ! k
--c
--          do k = 1,lv
--            w(iv+k-1) = w(ivi+k-1)
--          enddo ! k
--c
--          do k = 1,ls
--            w(is+k-1) = w(isi+k-1)
--          enddo ! k
--c
--c
--        endif ! krank .gt. 0
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddp_asvd0(m,n,a,krank,list,proj,u,v,s,ier,
--     1                        col,work)
--c
--c       routine iddp_asvd serves as a memory wrapper
--c       for the present routine (please see routine iddp_asvd
--c       for further documentation).
--c
--        implicit none
--        integer m,n,krank,list(n),ier
--        real*8 a(m,n),u(m,krank),v(n,krank),
--     1         s(krank),proj(krank,n-krank),col(m,krank),
--     2         work((krank+1)*(m+3*n)+26*krank**2)
--c
--c
--c       Collect together the columns of a indexed by list into col.
--c
--        call idd_copycols(m,n,a,krank,list,col)
--c
--c
--c       Convert the ID to an SVD.
--c
--        call idd_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/iddp_rid.f b/scipy/linalg/src/id_dist/src/iddp_rid.f
-deleted file mode 100644
-index 93b255f15..000000000
---- a/scipy/linalg/src/id_dist/src/iddp_rid.f
-+++ /dev/null
-@@ -1,376 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddp_rid computes the ID, to a specified precision,
--c       of a matrix specified by a routine for applying its transpose
--c       to arbitrary vectors. This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine iddp_rid(lproj,eps,m,n,matvect,p1,p2,p3,p4,
--     1                      krank,list,proj,ier)
--c
--c       computes the ID of a, i.e., lists in list the indices
--c       of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                        krank
--c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
--c                         l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon dimensioned epsilon(m,n-krank)
--c       such that the greatest singular value of epsilon
--c       <= the greatest singular value of a * eps.
--c
--c       input:
--c       lproj -- maximum usable length (in real*8 elements)
--c                of the array proj
--c       eps -- precision to which the ID is to be computed
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       matvect -- routine which applies the transpose
--c                  of the matrix to be ID'd to an arbitrary vector;
--c                  this routine must have a calling sequence
--c                  of the form
--c
--c                  matvect(m,x,n,y,p1,p2,p3,p4),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the transpose
--c                  of the matrix is to be applied,
--c                  n is the length of y,
--c                  y is the product of the transposed matrix and x,
--c                  and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvect
--c       p2 -- parameter to be passed to routine matvect
--c       p3 -- parameter to be passed to routine matvect
--c       p4 -- parameter to be passed to routine matvect
--c
--c       output:
--c       krank -- numerical rank
--c       list -- indices of the columns in the ID
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns
--c               in the original matrix being ID'd;
--c               the present routine uses proj as a work array, too, so
--c               proj must be at least m+1 + 2*n*(krank+1) real*8
--c               elements long, where krank is the rank output
--c               by the present routine
--c       ier -- 0 when the routine terminates successfully;
--c              -1000 when lproj is too small
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c               proj must be at least m+1 + 2*n*(krank+1) real*8
--c               elements long, where krank is the rank output
--c               by the present routine.
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,n,list(n),krank,lw,iwork,lwork,ira,kranki,lproj,
--     1          lra,ier,k
--        real*8 eps,p1,p2,p3,p4,proj(*)
--        external matvect
--c
--c
--        ier = 0
--c
--c
--c       Allocate memory in proj.
--c
--        lw = 0
--c
--        iwork = lw+1
--        lwork = m+2*n+1
--        lw = lw+lwork
--c
--        ira = lw+1
--c
--c
--c       Find the rank of a.
--c
--        lra = lproj-lwork
--        call idd_findrank(lra,eps,m,n,matvect,p1,p2,p3,p4,
--     1                    kranki,proj(ira),ier,proj(iwork))
--        if(ier .ne. 0) return
--c
--c
--        if(lproj .lt. lwork+2*kranki*n) then
--          ier = -1000
--          return
--        endif
--c
--c
--c       Transpose ra.
--c
--        call idd_rtransposer(n,kranki,proj(ira),proj(ira+kranki*n))
--c
--c
--c       Move the tranposed matrix to the beginning of proj.
--c
--        do k = 1,kranki*n
--          proj(k) = proj(ira+kranki*n+k-1)
--        enddo ! k
--c
--c
--c       ID the transposed matrix.
--c
--        call iddp_id(eps,kranki,n,proj,krank,list,proj(1+kranki*n))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_findrank(lra,eps,m,n,matvect,p1,p2,p3,p4,
--     1                          krank,ra,ier,w)
--c
--c       estimates the numerical rank krank of a matrix a to precision
--c       eps, where the routine matvect applies the transpose of a
--c       to an arbitrary vector. This routine applies the transpose of a
--c       to krank random vectors, and returns the resulting vectors
--c       as the columns of ra.
--c
--c       input:
--c       lra -- maximum usable length (in real*8 elements) of array ra
--c       eps -- precision defining the numerical rank
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       matvect -- routine which applies the transpose
--c                  of the matrix whose rank is to be estimated
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matvect(m,x,n,y,p1,p2,p3,p4),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the transpose
--c                  of the matrix is to be applied,
--c                  n is the length of y,
--c                  y is the product of the transposed matrix and x,
--c                  and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvect
--c       p2 -- parameter to be passed to routine matvect
--c       p3 -- parameter to be passed to routine matvect
--c       p4 -- parameter to be passed to routine matvect
--c
--c       output:
--c       krank -- estimate of the numerical rank of a
--c       ra -- product of the transpose of a and a matrix whose entries
--c             are pseudorandom realizations of i.i.d. random numbers,
--c             uniformly distributed on [0,1];
--c             ra must be at least 2*n*krank real*8 elements long
--c       ier -- 0 when the routine terminates successfully;
--c              -1000 when lra is too small
--c
--c       work:
--c       w -- must be at least m+2*n+1 real*8 elements long
--c
--c       _N.B._: ra must be at least 2*n*krank real*8 elements long.
--c               Also, the algorithm used by this routine is randomized.
--c
--        implicit none
--        integer m,n,lw,krank,ix,lx,iy,ly,iscal,lscal,lra,ier
--        real*8 eps,p1,p2,p3,p4,ra(n,*),w(m+2*n+1)
--        external matvect
--c
--c
--        lw = 0
--c
--        ix = lw+1
--        lx = m
--        lw = lw+lx
--c
--        iy = lw+1
--        ly = n
--        lw = lw+ly
--c
--        iscal = lw+1
--        lscal = n+1
--        lw = lw+lscal
--c
--c
--        call idd_findrank0(lra,eps,m,n,matvect,p1,p2,p3,p4,
--     1                     krank,ra,ier,w(ix),w(iy),w(iscal))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_findrank0(lra,eps,m,n,matvect,p1,p2,p3,p4,
--     1                           krank,ra,ier,x,y,scal)
--c
--c       routine idd_findrank serves as a memory wrapper
--c       for the present routine. (Please see routine idd_findrank
--c       for further documentation.)
--c
--        implicit none
--        integer m,n,krank,ifrescal,k,lra,ier
--        real*8 x(m),ra(n,2,*),p1,p2,p3,p4,scal(n+1),y(n),eps,residual,
--     1         enorm
--        external matvect
--c
--c
--        ier = 0
--c
--c
--        krank = 0
--c
--c
--c       Loop until the relative residual is greater than eps,
--c       or krank = m or krank = n.
--c
-- 1000   continue
--c
--c
--          if(lra .lt. n*2*(krank+1)) then
--            ier = -1000
--            return
--          endif
--c
--c
--c         Apply the transpose of a to a random vector.
--c
--          call id_srand(m,x)
--          call matvect(m,x,n,ra(1,1,krank+1),p1,p2,p3,p4)
--c
--          do k = 1,n
--            y(k) = ra(k,1,krank+1)
--          enddo ! k
--c
--c
--          if(krank .eq. 0) then
--c
--c           Compute the Euclidean norm of y.
--c
--            enorm = 0
--c
--            do k = 1,n
--              enorm = enorm + y(k)**2
--            enddo ! k
--c
--            enorm = sqrt(enorm)
--c
--          endif ! krank .eq. 0
--c
--c
--          if(krank .gt. 0) then
--c
--c           Apply the previous Householder transformations to y.
--c
--            ifrescal = 0
--c
--            do k = 1,krank
--              call idd_houseapp(n-k+1,ra(1,2,k),y(k),
--     1                          ifrescal,scal(k),y(k))
--            enddo ! k
--c
--          endif ! krank .gt. 0
--c
--c
--c         Compute the Householder vector associated with y.
--c
--          call idd_house(n-krank,y(krank+1),
--     1                   residual,ra(1,2,krank+1),scal(krank+1))
--          residual = abs(residual)
--c
--c
--          krank = krank+1
--c
--c
--        if(residual .gt. eps*enorm
--     1   .and. krank .lt. m .and. krank .lt. n)
--     2   goto 1000
--c
--c
--c       Delete the Householder vectors from the array ra.
--c
--        call idd_crunch(n,krank,ra)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_crunch(n,l,a)
--c
--c       removes every other block of n entries from a vector.
--c
--c       input:
--c       n -- length of each block to remove
--c       l -- half of the total number of blocks
--c       a -- original array
--c
--c       output:
--c       a -- array with every other block of n entries removed
--c
--        implicit none
--        integer j,k,n,l
--        real*8 a(n,2*l)
--c
--c
--        do j = 2,l
--          do k = 1,n
--c
--            a(k,j) = a(k,2*j-1)
--c
--          enddo ! k
--        enddo ! j
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idd_rtransposer(m,n,a,at)
--c
--c       transposes a to obtain at.
--c
--c       input:
--c       m -- first dimension of a, and second dimension of at
--c       n -- second dimension of a, and first dimension of at
--c       a -- matrix to be transposed
--c
--c       output:
--c       at -- transpose of a
--c
--        implicit none
--        integer m,n,j,k
--        real*8 a(m,n),at(n,m)
--c
--c
--        do k = 1,n
--          do j = 1,m
--c
--            at(k,j) = a(j,k)
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/iddp_rsvd.f b/scipy/linalg/src/id_dist/src/iddp_rsvd.f
-deleted file mode 100644
-index 8af9ba04c..000000000
---- a/scipy/linalg/src/id_dist/src/iddp_rsvd.f
-+++ /dev/null
-@@ -1,216 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddp_rsvd computes the SVD, to a specified precision,
--c       of a matrix specified by routines for applying the matrix
--c       and its transpose to arbitrary vectors.
--c       This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine iddp_rsvd(lw,eps,m,n,matvect,p1t,p2t,p3t,p4t,
--     1                       matvec,p1,p2,p3,p4,krank,iu,iv,is,w,ier)
--c
--c       constructs a rank-krank SVD  U Sigma V^T  approximating a
--c       to precision eps, where matvect is a routine which applies a^T
--c       to an arbitrary vector, and matvec is a routine
--c       which applies a to an arbitrary vector; U is an m x krank
--c       matrix whose columns are orthonormal, V is an n x krank
--c       matrix whose columns are orthonormal, and Sigma is a diagonal
--c       krank x krank matrix whose entries are all nonnegative.
--c       The entries of U are stored in w, starting at w(iu);
--c       the entries of V are stored in w, starting at w(iv).
--c       The diagonal entries of Sigma are stored in w,
--c       starting at w(is). This routine uses a randomized algorithm.
--c
--c       input:
--c       lw -- maximum usable length (in real*8 elements)
--c             of the array w
--c       eps -- precision of the desired approximation
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       matvect -- routine which applies the transpose
--c                  of the matrix to be SVD'd
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matvect(m,x,n,y,p1t,p2t,p3t,p4t),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the transpose
--c                  of the matrix is to be applied,
--c                  n is the length of y,
--c                  y is the product of the transposed matrix and x,
--c                  and p1t, p2t, p3t, and p4t are user-specified
--c                  parameters
--c       p1t -- parameter to be passed to routine matvect
--c       p2t -- parameter to be passed to routine matvect
--c       p3t -- parameter to be passed to routine matvect
--c       p4t -- parameter to be passed to routine matvect
--c       matvec -- routine which applies the matrix to be SVD'd
--c                 to an arbitrary vector; this routine must have
--c                 a calling sequence of the form
--c
--c                 matvec(n,x,m,y,p1,p2,p3,p4),
--c
--c                 where n is the length of x,
--c                 x is the vector to which the matrix is to be applied,
--c                 m is the length of y,
--c                 y is the product of the matrix and x,
--c                 and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvec
--c       p2 -- parameter to be passed to routine matvec
--c       p3 -- parameter to be passed to routine matvec
--c       p4 -- parameter to be passed to routine matvec
--c
--c       output:
--c       krank -- rank of the SVD constructed
--c       iu -- index in w of the first entry of the matrix
--c             of orthonormal left singular vectors of a
--c       iv -- index in w of the first entry of the matrix
--c             of orthonormal right singular vectors of a
--c       is -- index in w of the first entry of the array
--c             of singular values of a
--c       w -- array containing the singular values and singular vectors
--c            of a; w doubles as a work array, and so must be at least
--c            (krank+1)*(3*m+5*n+1)+25*krank**2 real*8 elements long,
--c            where krank is the rank returned by the present routine
--c       ier -- 0 when the routine terminates successfully;
--c              -1000 when lw is too small;
--c              other nonzero values when idd_id2svd bombs
--c
--c       _N.B._: w must be at least (krank+1)*(3*m+5*n+1)+25*krank**2
--c               real*8 elements long, where krank is the rank
--c               returned by the present routine. Also, the algorithm
--c               used by the present routine is randomized.
--c
--        implicit none
--        integer m,n,krank,lw,lw2,ilist,llist,iproj,icol,lcol,lp,
--     1          iwork,lwork,ier,lproj,iu,iv,is,lu,lv,ls,iui,ivi,isi,k
--        real*8 eps,p1t,p2t,p3t,p4t,p1,p2,p3,p4,w(*)
--        external matvect,matvec
--c
--c
--c       Allocate some memory.
--c
--        lw2 = 0
--c
--        ilist = lw2+1
--        llist = n
--        lw2 = lw2+llist
--c
--        iproj = lw2+1
--c
--c
--c       ID a.
--c
--        lp = lw-lw2
--        call iddp_rid(lp,eps,m,n,matvect,p1t,p2t,p3t,p4t,krank,
--     1                w(ilist),w(iproj),ier)
--        if(ier .ne. 0) return
--c
--c
--        if(krank .gt. 0) then
--c
--c
--c         Allocate more memory.
--c
--          lproj = krank*(n-krank)
--          lw2 = lw2+lproj
--c
--          icol = lw2+1
--          lcol = m*krank
--          lw2 = lw2+lcol
--c
--          iui = lw2+1
--          lu = m*krank
--          lw2 = lw2+lu
--c
--          ivi = lw2+1
--          lv = n*krank
--          lw2 = lw2+lv
--c
--          isi = lw2+1
--          ls = krank
--          lw2 = lw2+ls
--c
--          iwork = lw2+1
--          lwork = (krank+1)*(m+3*n)+26*krank**2
--          lw2 = lw2+lwork
--c
--c
--          if(lw .lt. lw2) then
--            ier = -1000
--            return
--          endif
--c
--c
--          call iddp_rsvd0(m,n,matvect,p1t,p2t,p3t,p4t,
--     1                    matvec,p1,p2,p3,p4,krank,w(iui),w(ivi),
--     2                    w(isi),ier,w(ilist),w(iproj),w(icol),
--     3                    w(iwork))
--          if(ier .ne. 0) return
--c
--c
--          iu = 1
--          iv = iu+lu
--          is = iv+lv
--c
--c
--c         Copy the singular values and singular vectors
--c         into their proper locations.
--c
--          do k = 1,lu
--            w(iu+k-1) = w(iui+k-1)
--          enddo ! k
--c
--          do k = 1,lv
--            w(iv+k-1) = w(ivi+k-1)
--          enddo ! k
--c
--          do k = 1,ls
--            w(is+k-1) = w(isi+k-1)
--          enddo ! k
--c
--c
--        endif ! krank .gt. 0
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddp_rsvd0(m,n,matvect,p1t,p2t,p3t,p4t,
--     1                        matvec,p1,p2,p3,p4,krank,u,v,s,ier,
--     2                        list,proj,col,work)
--c
--c       routine iddp_rsvd serves as a memory wrapper
--c       for the present routine (please see routine iddp_rsvd
--c       for further documentation).
--c
--        implicit none
--        integer m,n,krank,list(n),ier
--        real*8 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
--     1         s(krank),proj(krank,n-krank),col(m*krank),
--     2         work((krank+1)*(m+3*n)+26*krank**2)
--        external matvect,matvec
--c
--c
--c       Collect together the columns of a indexed by list into col.
--c
--        call idd_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,col,work)
--c
--c
--c       Convert the ID to an SVD.
--c
--        call idd_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/iddr_aid.f b/scipy/linalg/src/id_dist/src/iddr_aid.f
-deleted file mode 100644
-index 2dc811148..000000000
---- a/scipy/linalg/src/id_dist/src/iddr_aid.f
-+++ /dev/null
-@@ -1,208 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddr_aid computes the ID, to a specified rank,
--c       of an arbitrary matrix. This routine is randomized.
--c
--c       routine iddr_aidi initializes routine iddr_aid.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine iddr_aid(m,n,a,krank,w,list,proj)
--c
--c       computes the ID of the matrix a, i.e., lists in list
--c       the indices of krank columns of a such that 
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                       min(m,n,krank)
--c       a(j,list(k))  =     Sigma      a(j,list(l)) * proj(l,k-krank)(*)
--c                            l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
--c       whose norm is (hopefully) minimized by the pivoting procedure.
--c
--c       input:
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       a -- matrix to be ID'd; the present routine does not alter a
--c       krank -- rank of the ID to be constructed
--c       w -- initialization array that routine iddr_aidi
--c            has constructed
--c
--c       output:
--c       list -- indices of the columns in the ID
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns
--c               in the original matrix being ID'd
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,n,krank,list(n),lw,ir,lr,lw2,iw
--        real*8 a(m,n),proj(krank*(n-krank)),w((2*krank+17)*n+27*m+100)
--c
--c
--c       Allocate memory in w.
--c
--        lw = 0
--c
--        iw = lw+1
--        lw2 = 27*m+100+n
--        lw = lw+lw2
--c
--        ir = lw+1
--        lr = (krank+8)*2*n
--        lw = lw+lr
--c
--c
--        call iddr_aid0(m,n,a,krank,w(iw),list,proj,w(ir))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddr_aid0(m,n,a,krank,w,list,proj,r)
--c
--c       routine iddr_aid serves as a memory wrapper
--c       for the present routine
--c       (see iddr_aid for further documentation).
--c
--        implicit none
--        integer k,l,m,n2,n,krank,list(n),mn,lproj
--        real*8 a(m,n),r(krank+8,2*n),proj(krank,n-krank),
--     1         w(27*m+100+n)
--c
--c       Please note that the second dimension of r is 2*n
--c       (instead of n) so that if krank+8 >= m/2, then
--c       we can copy the whole of a into r.
--c
--c
--c       Retrieve the number of random test vectors
--c       and the greatest integer less than m that is
--c       a positive integer power of two.
--c
--        l = w(1)
--        n2 = w(2)
--c
--c
--        if(l .lt. n2 .and. l .le. m) then
--c
--c         Apply the random matrix.
--c
--          do k = 1,n
--            call idd_sfrm(l,m,n2,w(11),a(1,k),r(1,k))
--          enddo ! k
--c
--c         ID r.
--c
--          call iddr_id(l,n,r,krank,list,w(26*m+101))
--c
--c         Retrieve proj from r.
--c
--          lproj = krank*(n-krank)
--          call iddr_copydarr(lproj,r,proj)
--c
--        endif
--c
--c
--        if(l .ge. n2 .or. l .gt. m) then
--c
--c         ID a directly.
--c
--          mn = m*n
--          call iddr_copydarr(mn,a,r)
--          call iddr_id(m,n,r,krank,list,w(26*m+101))
--c
--c         Retrieve proj from r.
--c
--          lproj = krank*(n-krank)
--          call iddr_copydarr(lproj,r,proj)
--c
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddr_copydarr(n,a,b)
--c
--c       copies a into b.
--c
--c       input:
--c       n -- length of a and b
--c       a -- array to copy into b
--c
--c       output:
--c       b -- copy of a
--c
--        implicit none
--        integer n,k
--        real*8 a(n),b(n)
--c
--c
--        do k = 1,n
--          b(k) = a(k)
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddr_aidi(m,n,krank,w)
--c
--c       initializes the array w for using routine iddr_aid.
--c
--c       input:
--c       m -- number of rows in the matrix to be ID'd
--c       n -- number of columns in the matrix to be ID'd
--c       krank -- rank of the ID to be constructed
--c
--c       output:
--c       w -- initialization array for using routine iddr_aid
--c
--        implicit none
--        integer m,n,krank,l,n2
--        real*8 w((2*krank+17)*n+27*m+100)
--c
--c
--c       Set the number of random test vectors to 8 more than the rank.
--c
--        l = krank+8
--        w(1) = l
--c
--c
--c       Initialize the rest of the array w.
--c
--        n2 = 0
--        if(l .le. m) call idd_sfrmi(l,m,n2,w(11))
--        w(2) = n2
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/iddr_asvd.f b/scipy/linalg/src/id_dist/src/iddr_asvd.f
-deleted file mode 100644
-index 9641f0cd6..000000000
---- a/scipy/linalg/src/id_dist/src/iddr_asvd.f
-+++ /dev/null
-@@ -1,114 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddr_aid computes the SVD, to a specified rank,
--c       of an arbitrary matrix. This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine iddr_asvd(m,n,a,krank,w,u,v,s,ier)
--c
--c       constructs a rank-krank SVD  u diag(s) v^T  approximating a,
--c       where u is an m x krank matrix whose columns are orthonormal,
--c       v is an n x krank matrix whose columns are orthonormal,
--c       and diag(s) is a diagonal krank x krank matrix whose entries
--c       are all nonnegative. This routine uses a randomized algorithm.
--c
--c       input:
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       a -- matrix to be decomposed; the present routine does not
--c            alter a
--c       krank -- rank of the SVD being constructed
--c       w -- initialization array that routine iddr_aidi
--c            has constructed (for use in the present routine, w must
--c            be at least (2*krank+28)*m+(6*krank+21)*n+25*krank**2+100
--c            real*8 elements long)
--c
--c       output:
--c       u -- matrix of orthonormal left singular vectors of a
--c       v -- matrix of orthonormal right singular vectors of a
--c       s -- array of singular values of a
--c       ier -- 0 when the routine terminates successfully;
--c              nonzero otherwise
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c
--        implicit none
--        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
--     1          iwork,lwork,iwinit,lwinit,ier
--        real*8 a(m,n),u(m,krank),v(n,krank),s(krank),
--     1         w((2*krank+28)*m+(6*krank+21)*n+25*krank**2+100)
--c
--c
--c       Allocate memory in w.
--c
--        lw = 0
--c
--        iwinit = lw+1
--        lwinit = (2*krank+17)*n+27*m+100
--        lw = lw+lwinit
--c
--        ilist = lw+1
--        llist = n
--        lw = lw+llist
--c
--        iproj = lw+1
--        lproj = krank*(n-krank)
--        lw = lw+lproj
--c
--        icol = lw+1
--        lcol = m*krank
--        lw = lw+lcol
--c
--        iwork = lw+1
--        lwork = (krank+1)*(m+3*n)+26*krank**2
--        lw = lw+lwork
--c
--c
--        call iddr_asvd0(m,n,a,krank,w(iwinit),u,v,s,ier,
--     1                  w(ilist),w(iproj),w(icol),w(iwork))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddr_asvd0(m,n,a,krank,winit,u,v,s,ier,
--     1                        list,proj,col,work)
--c
--c       routine iddr_asvd serves as a memory wrapper
--c       for the present routine (please see routine iddr_asvd
--c       for further documentation).
--c
--        implicit none
--        integer m,n,krank,list(n),ier
--        real*8 a(m,n),u(m,krank),v(n,krank),s(krank),
--     1         proj(krank,n-krank),col(m*krank),
--     2         winit((2*krank+17)*n+27*m+100),
--     3         work((krank+1)*(m+3*n)+26*krank**2)
--c
--c
--c       ID a.
--c
--        call iddr_aid(m,n,a,krank,winit,list,proj)
--c
--c
--c       Collect together the columns of a indexed by list into col.
--c
--        call idd_copycols(m,n,a,krank,list,col)
--c
--c
--c       Convert the ID to an SVD.
--c
--        call idd_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/iddr_rid.f b/scipy/linalg/src/id_dist/src/iddr_rid.f
-deleted file mode 100644
-index eb96c145a..000000000
---- a/scipy/linalg/src/id_dist/src/iddr_rid.f
-+++ /dev/null
-@@ -1,155 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddr_rid computes the ID, to a specified rank,
--c       of a matrix specified by a routine for applying its transpose
--c       to arbitrary vectors. This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine iddr_rid(m,n,matvect,p1,p2,p3,p4,krank,list,proj)
--c
--c       computes the ID of a matrix "a" specified by
--c       the routine matvect -- matvect must apply the transpose
--c       of the matrix being ID'd to an arbitrary vector --
--c       i.e., the present routine lists in list the indices
--c       of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                       min(m,n,krank)
--c       a(j,list(k))  =     Sigma      a(j,list(l)) * proj(l,k-krank)(*)
--c                            l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
--c       whose norm is (hopefully) minimized by the pivoting procedure.
--c
--c       input:
--c       m -- number of rows in the matrix to be ID'd
--c       n -- number of columns in the matrix to be ID'd
--c       matvect -- routine which applies the transpose
--c                  of the matrix to be ID'd to an arbitrary vector;
--c                  this routine must have a calling sequence
--c                  of the form
--c
--c                  matvect(m,x,n,y,p1,p2,p3,p4),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the transpose
--c                  of the matrix is to be applied,
--c                  n is the length of y,
--c                  y is the product of the transposed matrix and x,
--c                  and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvect
--c       p2 -- parameter to be passed to routine matvect
--c       p3 -- parameter to be passed to routine matvect
--c       p4 -- parameter to be passed to routine matvect
--c       krank -- rank of the ID to be constructed
--c
--c       output:
--c       list -- indices of the columns in the ID
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns
--c               in the original matrix being ID'd;
--c               proj doubles as a work array in the present routine, so
--c               proj must be at least m+(krank+3)*n real*8 elements
--c               long
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c               proj must be at least m+(krank+3)*n real*8 elements
--c               long.
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,n,krank,list(n),lw,ix,lx,iy,ly,ir,lr
--        real*8 p1,p2,p3,p4,proj(m+(krank+3)*n)
--        external matvect
--c
--c
--c       Allocate memory in w.
--c
--        lw = 0
--c
--        ir = lw+1
--        lr = (krank+2)*n
--        lw = lw+lr
--c
--        ix = lw+1
--        lx = m
--        lw = lw+lx
--c
--        iy = lw+1
--        ly = n
--        lw = lw+ly
--c
--c
--        call iddr_ridall0(m,n,matvect,p1,p2,p3,p4,krank,
--     1                    list,proj(ir),proj(ix),proj(iy))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddr_ridall0(m,n,matvect,p1,p2,p3,p4,krank,
--     1                          list,r,x,y)
--c
--c       routine iddr_ridall serves as a memory wrapper
--c       for the present routine
--c       (see iddr_ridall for further documentation).
--c
--        implicit none
--        integer j,k,l,m,n,krank,list(n)
--        real*8 x(m),y(n),p1,p2,p3,p4,r(krank+2,n)
--        external matvect
--c
--c
--c       Set the number of random test vectors to 2 more than the rank.
--c
--        l = krank+2
--c
--c       Apply the transpose of the original matrix to l random vectors.
--c
--        do j = 1,l
--c
--c         Generate a random vector.
--c
--          call id_srand(m,x)
--c
--c         Apply the transpose of the matrix to x, obtaining y.
--c
--          call matvect(m,x,n,y,p1,p2,p3,p4)
--c
--c         Copy y into row j of r.
--c
--          do k = 1,n
--            r(j,k) = y(k)
--          enddo ! k
--c
--        enddo ! j
--c
--c
--c       ID r.
--c
--        call iddr_id(l,n,r,krank,list,y)
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/iddr_rsvd.f b/scipy/linalg/src/id_dist/src/iddr_rsvd.f
-deleted file mode 100644
-index 000ce8693..000000000
---- a/scipy/linalg/src/id_dist/src/iddr_rsvd.f
-+++ /dev/null
-@@ -1,157 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine iddr_rsvd computes the SVD, to a specified rank,
--c       of a matrix specified by routines for applying the matrix
--c       and its transpose to arbitrary vectors.
--c       This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine iddr_rsvd(m,n,matvect,p1t,p2t,p3t,p4t,
--     1                       matvec,p1,p2,p3,p4,krank,u,v,s,ier,w)
--c
--c       constructs a rank-krank SVD  u diag(s) v^T  approximating a,
--c       where matvect is a routine which applies a^T
--c       to an arbitrary vector, and matvec is a routine
--c       which applies a to an arbitrary vector;
--c       u is an m x krank matrix whose columns are orthonormal,
--c       v is an n x krank matrix whose columns are orthonormal,
--c       and diag(s) is a diagonal krank x krank matrix whose entries
--c       are all nonnegative. This routine uses a randomized algorithm.
--c
--c       input:
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       matvect -- routine which applies the transpose
--c                  of the matrix to be SVD'd
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matvect(m,x,n,y,p1t,p2t,p3t,p4t),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the transpose
--c                  of the matrix is to be applied,
--c                  n is the length of y,
--c                  y is the product of the transposed matrix and x,
--c                  and p1t, p2t, p3t, and p4t are user-specified
--c                  parameters
--c       p1t -- parameter to be passed to routine matvect
--c       p2t -- parameter to be passed to routine matvect
--c       p3t -- parameter to be passed to routine matvect
--c       p4t -- parameter to be passed to routine matvect
--c       matvec -- routine which applies the matrix to be SVD'd
--c                 to an arbitrary vector; this routine must have
--c                 a calling sequence of the form
--c
--c                 matvec(n,x,m,y,p1,p2,p3,p4),
--c
--c                 where n is the length of x,
--c                 x is the vector to which the matrix is to be applied,
--c                 m is the length of y,
--c                 y is the product of the matrix and x,
--c                 and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvec
--c       p2 -- parameter to be passed to routine matvec
--c       p3 -- parameter to be passed to routine matvec
--c       p4 -- parameter to be passed to routine matvec
--c       krank -- rank of the SVD being constructed
--c
--c       output:
--c       u -- matrix of orthonormal left singular vectors of a
--c       v -- matrix of orthonormal right singular vectors of a
--c       s -- array of singular values of a
--c       ier -- 0 when the routine terminates successfully;
--c              nonzero otherwise
--c
--c       work:
--c       w -- must be at least (krank+1)*(2*m+4*n)+25*krank**2
--c            real*8 elements long
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c
--        implicit none
--        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
--     1          iwork,lwork,ier
--        real*8 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
--     1         s(krank),w((krank+1)*(2*m+4*n)+25*krank**2)
--        external matvect,matvec
--c
--c
--c       Allocate memory in w.
--c
--        lw = 0
--c
--        ilist = lw+1
--        llist = n
--        lw = lw+llist
--c
--        iproj = lw+1
--        lproj = krank*(n-krank)
--        lw = lw+lproj
--c
--        icol = lw+1
--        lcol = m*krank
--        lw = lw+lcol
--c
--        iwork = lw+1
--        lwork = (krank+1)*(m+3*n)+26*krank**2
--        lw = lw+lwork
--c
--c
--        call iddr_rsvd0(m,n,matvect,p1t,p2t,p3t,p4t,
--     1                  matvec,p1,p2,p3,p4,krank,u,v,s,ier,
--     2                  w(ilist),w(iproj),w(icol),w(iwork))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine iddr_rsvd0(m,n,matvect,p1t,p2t,p3t,p4t,
--     1                        matvec,p1,p2,p3,p4,krank,u,v,s,ier,
--     2                        list,proj,col,work)
--c
--c       routine iddr_rsvd serves as a memory wrapper
--c       for the present routine (please see routine iddr_rsvd
--c       for further documentation).
--c
--        implicit none
--        integer m,n,krank,list(n),ier,k
--        real*8 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
--     1         s(krank),proj(krank*(n-krank)),col(m*krank),
--     2         work((krank+1)*(m+3*n)+26*krank**2)
--        external matvect,matvec
--c
--c
--c       ID a.
--c
--        call iddr_rid(m,n,matvect,p1t,p2t,p3t,p4t,krank,list,work)
--c
--c
--c       Retrieve proj from work.
--c
--        do k = 1,krank*(n-krank)
--          proj(k) = work(k)
--        enddo ! k
--c
--c
--c       Collect together the columns of a indexed by list into col.
--c
--        call idd_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,col,work)
--c
--c
--c       Convert the ID to an SVD.
--c
--        call idd_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idz_frm.f b/scipy/linalg/src/id_dist/src/idz_frm.f
-deleted file mode 100644
-index 93c4d8ec7..000000000
---- a/scipy/linalg/src/id_dist/src/idz_frm.f
-+++ /dev/null
-@@ -1,419 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idz_frm transforms a vector via a composition
--c       of Rokhlin's random transform, random subselection, and an FFT.
--c
--c       routine idz_sfrm transforms a vector into a vector
--c       of specified length via a composition
--c       of Rokhlin's random transform, random subselection, and an FFT.
--c
--c       routine idz_frmi initializes routine idz_frm.
--c
--c       routine idz_sfrmi initializes routine idz_sfrm.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idz_frm(m,n,w,x,y)
--c
--c       transforms x into y via a composition
--c       of Rokhlin's random transform, random subselection, and an FFT.
--c       In contrast to routine idz_sfrm, the present routine works best
--c       when the length of the transformed vector is the integer n
--c       output by routine idz_frmi, or when the length
--c       is not specified, but instead determined a posteriori
--c       using the output of the present routine. The transformed vector
--c       output by the present routine is randomly permuted.
--c
--c       input:
--c       m -- length of x
--c       n -- greatest integer expressible as a positive integer power
--c            of 2 that is less than or equal to m, as obtained
--c            from the routine idz_frmi; n is the length of y
--c       w -- initialization array constructed by routine idz_frmi
--c       x -- vector to be transformed
--c
--c       output:
--c       y -- transform of x
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,iw,n,k
--        complex*16 w(17*m+70),x(m),y(n)
--c
--c
--c       Apply Rokhlin's random transformation to x, obtaining
--c       w(16*m+71 : 17*m+70).
--c
--        iw = w(3+m+n)
--        call idz_random_transf(x,w(16*m+70+1),w(iw))
--c
--c
--c       Subselect from  w(16*m+71 : 17*m+70)  to obtain y.
--c
--        call idz_subselect(n,w(3),m,w(16*m+70+1),y)
--c
--c
--c       Copy y into  w(16*m+71 : 16*m+n+70).
--c
--        do k = 1,n
--          w(16*m+70+k) = y(k)
--        enddo ! k
--c
--c
--c       Fourier transform  w(16*m+71 : 16*m+n+70).
--c
--        call zfftf(n,w(16*m+70+1),w(4+m+n))
--c
--c
--c       Permute  w(16*m+71 : 16*m+n+70)  to obtain y.
--c
--        call idz_permute(n,w(3+m),w(16*m+70+1),y)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_sfrm(l,m,n,w,x,y)
--c
--c       transforms x into y via a composition
--c       of Rokhlin's random transform, random subselection, and an FFT.
--c       In contrast to routine idz_frm, the present routine works best
--c       when the length l of the transformed vector is known a priori.
--c
--c       input:
--c       l -- length of y; l must be less than or equal to n
--c       m -- length of x
--c       n -- greatest integer expressible as a positive integer power
--c            of 2 that is less than or equal to m, as obtained
--c            from the routine idz_frmi
--c       w -- initialization array constructed by routine idz_sfrmi
--c       x -- vector to be transformed
--c
--c       output:
--c       y -- transform of x
--c
--c       _N.B._: l must be less than or equal to n.
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,iw,n,l
--        complex*16 w(21*m+70),x(m),y(l)
--c
--c
--c       Apply Rokhlin's random transformation to x, obtaining
--c       w(19*m+71 : 20*m+70).
--c
--        iw = w(4+m+l)
--        call idz_random_transf(x,w(19*m+70+1),w(iw))
--c
--c
--c       Subselect from  w(19*m+71 : 20*m+70)  to obtain
--c       w(20*m+71 : 20*m+n+70).
--c
--        call idz_subselect(n,w(4),m,w(19*m+70+1),w(20*m+70+1))
--c
--c
--c       Fourier transform  w(20*m+71 : 20*m+n+70).
--c
--        call idz_sfft(l,w(4+m),n,w(5+m+l),w(20*m+70+1))
--c
--c
--c       Copy the desired entries from  w(20*m+71 : 20*m+n+70)
--c       to y.
--c
--        call idz_subselect(l,w(4+m),n,w(20*m+70+1),y)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_permute(n,ind,x,y)
--c
--c       copy the entries of x into y, rearranged according
--c       to the permutation specified by ind.
--c
--c       input:
--c       n -- length of ind, x, and y
--c       ind -- permutation of n objects
--c       x -- vector to be permuted
--c
--c       output:
--c       y -- permutation of x
--c
--        implicit none
--        integer n,ind(n),k
--        complex*16 x(n),y(n)
--c
--c
--        do k = 1,n
--          y(k) = x(ind(k))
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_subselect(n,ind,m,x,y)
--c
--c       copies into y the entries of x indicated by ind.
--c
--c       input:
--c       n -- number of entries of x to copy into y
--c       ind -- indices of the entries in x to copy into y
--c       m -- length of x
--c       x -- vector whose entries are to be copied
--c
--c       output:
--c       y -- collection of entries of x specified by ind
--c
--        implicit none
--        integer n,ind(n),m,k
--        complex*16 x(m),y(n)
--c
--c
--        do k = 1,n
--          y(k) = x(ind(k))
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_frmi(m,n,w)
--c
--c       initializes data for the routine idz_frm.
--c
--c       input:
--c       m -- length of the vector to be transformed
--c
--c       output:
--c       n -- greatest integer expressible as a positive integer power
--c            of 2 that is less than or equal to m
--c       w -- initialization array to be used by routine idz_frm
--c
--c
--c       glossary for the fully initialized w:
--c
--c       w(1) = m
--c       w(2) = n
--c       w(3:2+m) stores a permutation of m objects
--c       w(3+m:2+m+n) stores a permutation of n objects
--c       w(3+m+n) = address in w of the initialization array
--c                  for idz_random_transf
--c       w(4+m+n:int(w(3+m+n))-1) stores the initialization array
--c                                for zfft
--c       w(int(w(3+m+n)):16*m+70) stores the initialization array
--c                                for idz_random_transf
--c
--c
--c       _N.B._: n is an output of the present routine;
--c               this routine changes n.
--c
--c
--        implicit none
--        integer m,n,l,nsteps,keep,lw,ia
--        complex*16 w(17*m+70)
--c
--c
--c       Find the greatest integer less than or equal to m
--c       which is a power of two.
--c
--        call idz_poweroftwo(m,l,n)
--c
--c
--c       Store m and n in w.
--c
--        w(1) = m
--        w(2) = n
--c
--c
--c       Store random permutations of m and n objects in w.
--c
--        call id_randperm(m,w(3))
--        call id_randperm(n,w(3+m))
--c
--c
--c       Store the address within w of the idz_random_transf_init
--c       initialization data.
--c
--        ia = 4+m+n+2*n+15
--        w(3+m+n) = ia
--c
--c
--c       Store the initialization data for zfft in w.
--c
--        call zffti(n,w(4+m+n))
--c
--c
--c       Store the initialization data for idz_random_transf_init in w.
--c
--        nsteps = 3
--        call idz_random_transf_init(nsteps,m,w(ia),keep)
--c
--c
--c       Calculate the total number of elements used in w.
--c
--        lw = 3+m+n+2*n+15 + 3*nsteps*m+2*m+m/4+50
--c
--        if(16*m+70 .lt. lw) then
--          call prinf('lw = *',lw,1)
--          call prinf('16m+70 = *',16*m+70,1)
--          stop
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_sfrmi(l,m,n,w)
--c
--c       initializes data for the routine idz_sfrm.
--c
--c       input:
--c       l -- length of the transformed (output) vector
--c       m -- length of the vector to be transformed
--c
--c       output:
--c       n -- greatest integer expressible as a positive integer power
--c            of 2 that is less than or equal to m
--c       w -- initialization array to be used by routine idz_sfrm
--c
--c
--c       glossary for the fully initialized w:
--c
--c       w(1) = m
--c       w(2) = n
--c       w(3) is unused
--c       w(4:3+m) stores a permutation of m objects
--c       w(4+m:3+m+l) stores the indices of the l outputs which idz_sfft
--c                    calculates
--c       w(4+m+l) = address in w of the initialization array
--c                  for idz_random_transf
--c       w(5+m+l:int(w(4+m+l))-1) stores the initialization array
--c                                for idz_sfft
--c       w(int(w(4+m+l)):19*m+70) stores the initialization array
--c                                for idz_random_transf
--c
--c
--c       _N.B._: n is an output of the present routine;
--c               this routine changes n.
--c
--c
--        implicit none
--        integer l,m,n,idummy,nsteps,keep,lw,ia
--        complex*16 w(21*m+70)
--c
--c
--c       Find the greatest integer less than or equal to m
--c       which is a power of two.
--c
--        call idz_poweroftwo(m,idummy,n)
--c
--c
--c       Store m and n in w.
--c
--        w(1) = m
--        w(2) = n
--        w(3) = 0
--c
--c
--c       Store random permutations of m and n objects in w.
--c
--        call id_randperm(m,w(4))
--        call id_randperm(n,w(4+m))
--c
--c
--c       Store the address within w of the idz_random_transf_init
--c       initialization data.
--c
--        ia = 5+m+l+2*l+15+3*n
--        w(4+m+l) = ia
--c
--c
--c       Store the initialization data for idz_sfft in w.
--c
--        call idz_sffti(l,w(4+m),n,w(5+m+l))
--c
--c
--c       Store the initialization data for idz_random_transf_init in w.
--c
--        nsteps = 3
--        call idz_random_transf_init(nsteps,m,w(ia),keep)
--c
--c
--c       Calculate the total number of elements used in w.
--c
--        lw = 4+m+l+2*l+15+3*n + 3*nsteps*m+2*m+m/4+50
--c
--        if(19*m+70 .lt. lw) then
--          call prinf('lw = *',lw,1)
--          call prinf('19m+70 = *',19*m+70,1)
--          stop
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_poweroftwo(m,l,n)
--c
--c       computes l = floor(log_2(m)) and n = 2**l.
--c
--c       input:
--c       m -- integer whose log_2 is to be taken
--c
--c       output:
--c       l -- floor(log_2(m))
--c       n -- 2**l
--c
--        implicit none
--        integer l,m,n
--c
--c
--        l = 0
--        n = 1
--c
-- 1000   continue
--          l = l+1
--          n = n*2
--        if(n .le. m) goto 1000
--c
--        l = l-1
--        n = n/2
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idz_house.f b/scipy/linalg/src/id_dist/src/idz_house.f
-deleted file mode 100644
-index 93db06e6d..000000000
---- a/scipy/linalg/src/id_dist/src/idz_house.f
-+++ /dev/null
-@@ -1,298 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idz_house calculates the vector and scalar
--c       needed to apply the Householder transformation reflecting
--c       a given vector into its first component.
--c
--c       routine idz_houseapp applies a Householder matrix to a vector.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idz_houseapp(n,vn,u,ifrescal,scal,v)
--c
--c       applies the Householder matrix
--c       identity_matrix - scal * vn * adjoint(vn)
--c       to the vector u, yielding the vector v;
--c
--c       scal = 2/(1 + |vn(2)|^2 + ... + |vn(n)|^2)
--c       when vn(2), ..., vn(n) don't all vanish;
--c
--c       scal = 0
--c       when vn(2), ..., vn(n) do all vanish
--c       (including when n = 1).
--c
--c       input:
--c       n -- size of vn, u, and v, though the indexing on vn goes
--c            from 2 to n
--c       vn -- components 2 to n of the Householder vector vn;
--c             vn(1) is assumed to be 1
--c       u -- vector to be transformed
--c       ifrescal -- set to 1 to recompute scal from vn(2), ..., vn(n);
--c                   set to 0 to use scal as input
--c       scal -- see the entry for ifrescal in the decription
--c               of the input
--c
--c       output:
--c       scal -- see the entry for ifrescal in the decription
--c               of the input
--c       v -- result of applying the Householder matrix to u;
--c            it's O.K. to have v be the same as u
--c            in order to apply the matrix to the vector in place
--c
--c       reference:
--c       Golub and Van Loan, "Matrix Computations," 3rd edition,
--c            Johns Hopkins University Press, 1996, Chapter 5.
--c
--        implicit none
--        save
--        integer n,k,ifrescal
--        real*8 scal,sum
--        complex*16 vn(2:*),u(n),v(n),fact
--c
--c
--c       Get out of this routine if n = 1.
--c
--        if(n .eq. 1) then
--          v(1) = u(1)
--          return
--        endif
--c
--c
--        if(ifrescal .eq. 1) then
--c
--c
--c         Calculate |vn(2)|^2 + ... + |vn(n)|^2.
--c
--          sum = 0
--          do k = 2,n
--            sum = sum+vn(k)*conjg(vn(k))
--          enddo ! k
--c
--c
--c         Calculate scal.
--c
--          if(sum .eq. 0) scal = 0
--          if(sum .ne. 0) scal = 2/(1+sum)
--c
--c
--        endif
--c
--c
--c       Calculate fact = scal * adjoint(vn) * u.
--c
--        fact = u(1)
--c
--        do k = 2,n
--          fact = fact+conjg(vn(k))*u(k)
--        enddo ! k
--c
--        fact = fact*scal
--c
--c
--c       Subtract fact*vn from u, yielding v.
--c
--        v(1) = u(1) - fact
--c
--        do k = 2,n
--          v(k) = u(k) - fact*vn(k)
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_house(n,x,css,vn,scal)
--c
--c       constructs the vector vn with vn(1) = 1,
--c       and the scalar scal, such that the obviously self-adjoint
--c       H := identity_matrix - scal * vn * adjoint(vn) is unitary,
--c       the absolute value of the first entry of Hx
--c       is the root-sum-square of the entries of x,
--c       and all other entries of Hx are zero
--c       (H is the Householder matrix corresponding to x).
--c
--c       input:
--c       n -- size of x and vn, though the indexing on vn goes
--c            from 2 to n
--c       x -- vector to reflect into its first component
--c
--c       output:
--c       css -- root-sum-square of the entries of x * the phase of x(1)
--c       vn -- entries 2 to n of the Householder vector vn;
--c             vn(1) is assumed to be 1
--c       scal -- scalar multiplying vn * adjoint(vn);
--c
--c               scal = 2/(1 + |vn(2)|^2 + ... + |vn(n)|^2)
--c               when vn(2), ..., vn(n) don't all vanish;
--c
--c               scal = 0
--c               when vn(2), ..., vn(n) do all vanish
--c               (including when n = 1)
--c
--c       reference:
--c       Golub and Van Loan, "Matrix Computations," 3rd edition,
--c            Johns Hopkins University Press, 1996, Chapter 5.
--c
--        implicit none
--        save
--        integer n,k
--        real*8 scal,test,rss,sum
--        complex*16 x(n),v1,vn(2:*),x1,phase,css
--c
--c
--        x1 = x(1)
--c
--c
--c       Get out of this routine if n = 1.
--c
--        if(n .eq. 1) then
--          css = x1
--          scal = 0
--          return
--        endif
--c
--c
--c       Calculate |x(2)|^2 + ... |x(n)|^2
--c       and the root-sum-square value of the entries in x.
--c
--c
--        sum = 0
--        do k = 2,n
--          sum = sum+x(k)*conjg(x(k))
--        enddo ! k
--c
--c
--c       Get out of this routine if sum = 0;
--c       flag this case as such by setting v(2), ..., v(n) all to 0.
--c
--        if(sum .eq. 0) then
--c
--          css = x1
--          do k = 2,n
--            vn(k) = 0
--          enddo ! k
--          scal = 0
--c
--          return
--c
--        endif
--c
--c
--        rss = x1*conjg(x1) + sum
--        rss = sqrt(rss)
--c
--c
--c       Determine the first component v1
--c       of the unnormalized Householder vector
--c       v = x - phase(x1) * rss * (1 0 0 ... 0 0)^T.
--c
--        if(x1 .eq. 0) phase = 1
--        if(x1 .ne. 0) phase = x1/abs(x1)
--        test = conjg(phase) * x1
--        css = phase*rss
--c
--c       If test <= 0, then form x1-phase*rss directly,
--c       since that expression cannot involve any cancellation.
--c
--        if(test .le. 0) v1 = x1-phase*rss
--c
--c       If test > 0, then use the fact that
--c       x1-phase*rss = -phase*sum / ((phase)^* * x1 + rss),
--c       in order to avoid potential cancellation.
--c
--        if(test .gt. 0) v1 = -phase*sum / (conjg(phase)*x1+rss)
--c
--c
--c       Compute the vector vn and the scalar scal such that vn(1) = 1
--c       in the Householder transformation
--c       identity_matrix - scal * vn * adjoint(vn).
--c
--        do k = 2,n
--          vn(k) = x(k)/v1
--        enddo ! k
--c
--c       scal = 2
--c            / ( |vn(1)|^2 + |vn(2)|^2 + ... + |vn(n)|^2 )
--c
--c            = 2
--c            / ( 1 + |vn(2)|^2 + ... + |vn(n)|^2 )
--c
--c            = 2*|v(1)|^2
--c            / ( |v(1)|^2 + |v(1)*vn(2)|^2 + ... + |v(1)*vn(n)|^2 )
--c
--c            = 2*|v(1)|^2
--c            / ( |v(1)|^2 + (|v(2)|^2 + ... + |v(n)|^2) )
--c
--        scal = 2*v1*conjg(v1) / (v1*conjg(v1)+sum)
--c
--c
--        rss = phase*rss
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_housemat(n,vn,scal,h)
--c
--c       fills h with the Householder matrix
--c       identity_matrix - scal * vn * adjoint(vn).
--c
--c       input:
--c       n -- size of vn and h, though the indexing of vn goes
--c            from 2 to n
--c       vn -- entries 2 to n of the vector vn;
--c             vn(1) is assumed to be 1
--c       scal -- scalar multiplying vn * adjoint(vn)
--c
--c       output:
--c       h -- identity_matrix - scal * vn * adjoint(vn)
--c
--        implicit none
--        save
--        integer n,j,k
--        real*8 scal
--        complex*16 vn(2:*),h(n,n),factor1,factor2
--c
--c
--c       Fill h with the identity matrix.
--c
--        do j = 1,n
--          do k = 1,n
--c
--            if(j .eq. k) h(k,j) = 1
--            if(j .ne. k) h(k,j) = 0
--c
--          enddo ! k
--        enddo ! j
--c
--c
--c       Subtract from h the matrix scal*vn*adjoint(vn).
--c
--        do j = 1,n
--          do k = 1,n
--c
--            if(j .eq. 1) factor1 = 1
--            if(j .ne. 1) factor1 = vn(j)
--c
--            if(k .eq. 1) factor2 = 1
--            if(k .ne. 1) factor2 = conjg(vn(k))
--c
--            h(k,j) = h(k,j) - scal*factor1*factor2
--c
--          enddo ! k
--        enddo ! j
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idz_id.f b/scipy/linalg/src/id_dist/src/idz_id.f
-deleted file mode 100644
-index 7a80243ff..000000000
---- a/scipy/linalg/src/id_dist/src/idz_id.f
-+++ /dev/null
-@@ -1,566 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzp_id computes the ID of a matrix,
--c       to a specified precision.
--c
--c       routine idzr_id computes the ID of a matrix,
--c       to a specified rank.
--c
--c       routine idz_reconid reconstructs a matrix from its ID.
--c
--c       routine idz_copycols collects together selected columns
--c       of a matrix.
--c
--c       routine idz_getcols collects together selected columns
--c       of a matrix specified by a routine for applying the matrix
--c       to arbitrary vectors.
--c
--c       routine idz_reconint constructs p in the ID a = b p,
--c       where the columns of b are a subset of the columns of a,
--c       and p is the projection coefficient matrix,
--c       given list, krank, and proj output by routines idzr_id
--c       or idzp_id.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idzp_id(eps,m,n,a,krank,list,rnorms)
--c
--c       computes the ID of a, i.e., lists in list the indices
--c       of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                        krank
--c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
--c                         l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon dimensioned epsilon(m,n-krank)
--c       such that the greatest singular value of epsilon
--c       <= the greatest singular value of a * eps.
--c       The present routine stores the krank x (n-krank) matrix proj
--c       in the memory initially occupied by a.
--c
--c       input:
--c       eps -- relative precision of the resulting ID
--c       m -- first dimension of a
--c       n -- second dimension of a, as well as the dimension required
--c            of list
--c       a -- matrix to be ID'd
--c
--c       output:
--c       a -- the first krank*(n-krank) elements of a constitute
--c            the krank x (n-krank) interpolation matrix proj
--c       krank -- numerical rank
--c       list -- list of the indices of the krank columns of a
--c               through which the other columns of a are expressed;
--c               also, list describes the permutation of proj
--c               required to reconstruct a as indicated in (*) above
--c       rnorms -- absolute values of the entries on the diagonal
--c                 of the triangular matrix used to compute the ID
--c                 (these may be used to check the stability of the ID)
--c
--c       _N.B._: This routine changes a.
--c
--c       reference:
--c       Cheng, Gimbutas, Martinsson, Rokhlin, "On the compression of
--c            low-rank matrices," SIAM Journal on Scientific Computing,
--c            26 (4): 1389-1404, 2005.
--c
--        implicit none
--        integer m,n,krank,k,list(n),iswap
--        real*8 eps,rnorms(n)
--        complex*16 a(m,n)
--c
--c
--c       QR decompose a.
--c
--        call idzp_qrpiv(eps,m,n,a,krank,list,rnorms)
--c
--c
--c       Build the list of columns chosen in a
--c       by multiplying together the permutations in list,
--c       with the permutation swapping 1 and list(1) taken rightmost
--c       in the product, that swapping 2 and list(2) taken next
--c       rightmost, ..., that swapping krank and list(krank) taken
--c       leftmost.
--c
--        do k = 1,n
--          rnorms(k) = k
--        enddo ! k
--c
--        if(krank .gt. 0) then
--          do k = 1,krank
--c
--c           Swap rnorms(k) and rnorms(list(k)).
--c
--            iswap = rnorms(k)
--            rnorms(k) = rnorms(list(k))
--            rnorms(list(k)) = iswap
--c
--          enddo ! k
--        endif
--c
--        do k = 1,n
--          list(k) = rnorms(k)
--        enddo ! k
--c
--c
--c       Fill rnorms for the output.
--c
--        if(krank .gt. 0) then
--c
--          do k = 1,krank
--            rnorms(k) = a(k,k)
--          enddo ! k
--c
--        endif
--c
--c
--c       Backsolve for proj, storing it at the beginning of a.
--c
--        if(krank .gt. 0) then
--          call idz_lssolve(m,n,a,krank)
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzr_id(m,n,a,krank,list,rnorms)
--c
--c       computes the ID of a, i.e., lists in list the indices
--c       of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                        krank
--c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
--c                         l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
--c       whose norm is (hopefully) minimized by the pivoting procedure.
--c       The present routine stores the krank x (n-krank) matrix proj
--c       in the memory initially occupied by a.
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a, as well as the dimension required
--c            of list
--c       a -- matrix to be ID'd
--c       krank -- desired rank of the output matrix
--c                (please note that if krank > m or krank > n,
--c                then the rank of the output matrix will be
--c                less than krank)
--c
--c       output:
--c       a -- the first krank*(n-krank) elements of a constitute
--c            the krank x (n-krank) interpolation matrix proj
--c       list -- list of the indices of the krank columns of a
--c               through which the other columns of a are expressed;
--c               also, list describes the permutation of proj
--c               required to reconstruct a as indicated in (*) above
--c       rnorms -- absolute values of the entries on the diagonal
--c                 of the triangular matrix used to compute the ID
--c                 (these may be used to check the stability of the ID)
--c
--c       _N.B._: This routine changes a.
--c
--c       reference:
--c       Cheng, Gimbutas, Martinsson, Rokhlin, "On the compression of
--c            low-rank matrices," SIAM Journal on Scientific Computing,
--c            26 (4): 1389-1404, 2005.
--c
--        implicit none
--        integer m,n,krank,j,k,list(n),iswap
--        real*8 rnorms(n),ss
--        complex*16 a(m,n)
--c
--c
--c       QR decompose a.
--c
--        call idzr_qrpiv(m,n,a,krank,list,rnorms)
--c
--c
--c       Build the list of columns chosen in a
--c       by multiplying together the permutations in list,
--c       with the permutation swapping 1 and list(1) taken rightmost
--c       in the product, that swapping 2 and list(2) taken next
--c       rightmost, ..., that swapping krank and list(krank) taken
--c       leftmost.
--c
--        do k = 1,n
--          rnorms(k) = k
--        enddo ! k
--c
--        if(krank .gt. 0) then
--          do k = 1,krank
--c
--c           Swap rnorms(k) and rnorms(list(k)).
--c
--            iswap = rnorms(k)
--            rnorms(k) = rnorms(list(k))
--            rnorms(list(k)) = iswap
--c
--          enddo ! k
--        endif
--c
--        do k = 1,n
--          list(k) = rnorms(k)
--        enddo ! k
--c
--c
--c       Fill rnorms for the output.
--c
--        ss = 0
--c
--        do k = 1,krank
--          rnorms(k) = a(k,k)
--          ss = ss + rnorms(k)**2
--        enddo ! k
--c
--c
--c       Backsolve for proj, storing it at the beginning of a.
--c
--        if(krank .gt. 0 .and. ss .gt. 0) then
--          call idz_lssolve(m,n,a,krank)
--        endif
--c
--        if(ss .eq. 0) then
--c
--          do k = 1,n
--            do j = 1,m
--c
--              a(j,k) = 0
--c
--            enddo ! j
--          enddo ! k
--c
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_reconid(m,krank,col,n,list,proj,approx)
--c
--c       reconstructs the matrix that the routine idzp_id
--c       or idzr_id has decomposed, using the columns col
--c       of the reconstructed matrix whose indices are listed in list,
--c       in addition to the interpolation matrix proj.
--c
--c       input:
--c       m -- first dimension of cols and approx
--c       krank -- first dimension of cols and proj; also,
--c                n-krank is the second dimension of proj
--c       col -- columns of the matrix to be reconstructed
--c       n -- second dimension of approx; also,
--c            n-krank is the second dimension of proj
--c       list(k) -- index of col(1:m,k) in the reconstructed matrix
--c                  when k <= krank; in general, list describes
--c                  the permutation required for reconstruction
--c                  via cols and proj
--c       proj -- interpolation matrix
--c
--c       output:
--c       approx -- reconstructed matrix
--c
--        implicit none
--        integer m,n,krank,j,k,l,list(n)
--        complex*16 col(m,krank),proj(krank,n-krank),approx(m,n)
--c
--c
--        do j = 1,m
--          do k = 1,n
--c
--            approx(j,list(k)) = 0
--c
--c           Add in the contributions due to the identity matrix.
--c
--            if(k .le. krank) then
--              approx(j,list(k)) = approx(j,list(k)) + col(j,k)
--            endif
--c
--c           Add in the contributions due to proj.
--c
--            if(k .gt. krank) then
--              if(krank .gt. 0) then
--c
--                do l = 1,krank
--                  approx(j,list(k)) = approx(j,list(k))
--     1                              + col(j,l)*proj(l,k-krank)
--                enddo ! l
--c
--              endif
--            endif
--c
--          enddo ! k
--        enddo ! j
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_lssolve(m,n,a,krank)
--c
--c       backsolves for proj satisfying R_11 proj ~ R_12,
--c       where R_11 = a(1:krank,1:krank)
--c       and R_12 = a(1:krank,krank+1:n).
--c       This routine overwrites the beginning of a with proj.
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a; also,
--c            n-krank is the second dimension of proj
--c       a -- trapezoidal input matrix
--c       krank -- first dimension of proj; also,
--c                n-krank is the second dimension of proj
--c
--c       output:
--c       a -- the first krank*(n-krank) elements of a constitute
--c            the krank x (n-krank) matrix proj
--c
--        implicit none
--        integer m,n,krank,j,k,l
--        real*8 rnumer,rdenom
--        complex*16 a(m,n),sum
--c
--c
--c       Overwrite a(1:krank,krank+1:n) with proj.
--c
--        do k = 1,n-krank
--          do j = krank,1,-1
--c
--            sum = 0
--c
--            do l = j+1,krank
--              sum = sum+a(j,l)*a(l,krank+k)
--            enddo ! l
--c
--            a(j,krank+k) = a(j,krank+k)-sum
--c
--c           Make sure that the entry in proj won't be too big;
--c           set the entry to 0 when roundoff would make it too big
--c           (in which case a(j,j) is so small that the contribution
--c           from this entry in proj to the overall matrix approximation
--c           is supposed to be negligible).
--c
--            rnumer = a(j,krank+k)*conjg(a(j,krank+k))
--            rdenom = a(j,j)*conjg(a(j,j))
--c
--            if(rnumer .lt. 2**30*rdenom) then
--              a(j,krank+k) = a(j,krank+k)/a(j,j)
--            else
--              a(j,krank+k) = 0
--            endif
--c
--          enddo ! j
--        enddo ! k
--c
--c
--c       Move proj from a(1:krank,krank+1:n) to the beginning of a.
--c
--        call idz_moverup(m,n,krank,a)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_moverup(m,n,krank,a)
--c
--c       moves the krank x (n-krank) matrix in a(1:krank,krank+1:n),
--c       where a is initially dimensioned m x n, to the beginning of a.
--c       (This is not the most natural way to code the move,
--c       but one of my usually well-behaved compilers chokes
--c       on more natural ways.)
--c
--c       input:
--c       m -- initial first dimension of a
--c       n -- initial second dimension of a
--c       krank -- number of rows to move
--c       a -- m x n matrix whose krank x (n-krank) block
--c            a(1:krank,krank+1:n) is to be moved
--c
--c       output:
--c       a -- array starting with the moved krank x (n-krank) block
--c
--        implicit none
--        integer m,n,krank,j,k
--        complex*16 a(m*n)
--c
--c
--        do k = 1,n-krank
--          do j = 1,krank
--            a(j+krank*(k-1)) = a(j+m*(krank+k-1))
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,
--     1                         col,x)
--c
--c       collects together the columns of the matrix a indexed by list
--c       into the matrix col, where routine matvec applies a
--c       to an arbitrary vector.
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       matvec -- routine which applies a to an arbitrary vector;
--c                 this routine must have a calling sequence of the form
--c
--c                 matvec(m,x,n,y,p1,p2,p3,p4)
--c
--c                 where m is the length of x,
--c                 x is the vector to which the matrix is to be applied,
--c                 n is the length of y,
--c                 y is the product of the matrix and x,
--c                 and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvec
--c       p2 -- parameter to be passed to routine matvec
--c       p3 -- parameter to be passed to routine matvec
--c       p4 -- parameter to be passed to routine matvec
--c       krank -- number of columns to be extracted
--c       list -- indices of the columns to be extracted
--c
--c       output:
--c       col -- columns of a indexed by list
--c
--c       work:
--c       x -- must be at least n complex*16 elements long
--c
--        implicit none
--        integer m,n,krank,list(krank),j,k
--        complex*16 col(m,krank),x(n),p1,p2,p3,p4
--        external matvec
--c
--c
--        do j = 1,krank
--c
--          do k = 1,n
--            x(k) = 0
--          enddo ! k
--c
--          x(list(j)) = 1
--c
--          call matvec(n,x,m,col(1,j),p1,p2,p3,p4)
--c
--        enddo ! j
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_reconint(n,list,krank,proj,p)
--c
--c       constructs p in the ID a = b p,
--c       where the columns of b are a subset of the columns of a,
--c       and p is the projection coefficient matrix,
--c       given list, krank, and proj output
--c       by routines idzp_id or idzr_id.
--c
--c       input:
--c       n -- part of the second dimension of proj and p
--c       list -- list of columns retained from the original matrix
--c               in the ID
--c       krank -- rank of the ID
--c       proj -- matrix of projection coefficients in the ID
--c
--c       output:
--c       p -- projection matrix in the ID
--c
--        implicit none
--        integer n,krank,list(n),j,k
--        complex*16 proj(krank,n-krank),p(krank,n)
--c
--c
--        do k = 1,krank
--          do j = 1,n
--c
--            if(j .le. krank) then
--              if(j .eq. k) p(k,list(j)) = 1
--              if(j .ne. k) p(k,list(j)) = 0
--            endif
--c
--            if(j .gt. krank) then
--              p(k,list(j)) = proj(k,j-krank)
--            endif
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_copycols(m,n,a,krank,list,col)
--c
--c       collects together the columns of the matrix a indexed by list
--c       into the matrix col.
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       a -- matrix whose columns are to be extracted
--c       krank -- number of columns to be extracted
--c       list -- indices of the columns to be extracted
--c
--c       output:
--c       col -- columns of a indexed by list
--c
--        implicit none
--        integer m,n,krank,list(krank),j,k
--        complex*16 a(m,n),col(m,krank)
--c
--c
--        do k = 1,krank
--          do j = 1,m
--c
--            col(j,k) = a(j,list(k))
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idz_id2svd.f b/scipy/linalg/src/id_dist/src/idz_id2svd.f
-deleted file mode 100644
-index 55832e5d1..000000000
---- a/scipy/linalg/src/id_dist/src/idz_id2svd.f
-+++ /dev/null
-@@ -1,389 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idz_id2svd converts an approximation to a matrix
--c       in the form of an ID to an approximation in the form of an SVD.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idz_id2svd(m,krank,b,n,list,proj,u,v,s,ier,w)
--c
--c       converts an approximation to a matrix in the form of an ID
--c       to an approximation in the form of an SVD.
--c
--c       input:
--c       m -- first dimension of b
--c       krank -- rank of the ID
--c       b -- columns of the original matrix in the ID
--c       list -- list of columns chosen from the original matrix
--c               in the ID
--c       n -- length of list and part of the second dimension of proj
--c       proj -- projection coefficients in the ID
--c
--c       output:
--c       u -- left singular vectors
--c       v -- right singular vectors
--c       s -- singular values
--c       ier -- 0 when the routine terminates successfully;
--c              nonzero otherwise
--c
--c       work:
--c       w -- must be at least (krank+1)*(m+3*n+10)+9*krank**2
--c            complex*16 elements long
--c
--c       _N.B._: This routine destroys b.
--c
--        implicit none
--        integer m,krank,n,list(n),iwork,lwork,ip,lp,it,lt,ir,lr,
--     1          ir2,lr2,ir3,lr3,iind,lind,iindt,lindt,lw,ier
--        real*8 s(krank)
--        complex*16 b(m,krank),proj(krank,n-krank),u(m,krank),
--     1             v(n,krank),w((krank+1)*(m+3*n+10)+9*krank**2)
--c
--c
--c       Allocate memory for idz_id2svd0.
--c
--        lw = 0
--c
--        iwork = lw+1
--        lwork = 8*krank**2+10*krank
--        lw = lw+lwork
--c
--        ip = lw+1
--        lp = krank*n
--        lw = lw+lp
--c
--        it = lw+1
--        lt = n*krank
--        lw = lw+lt
--c
--        ir = lw+1
--        lr = krank*n
--        lw = lw+lr
--c
--        ir2 = lw+1
--        lr2 = krank*m
--        lw = lw+lr2
--c
--        ir3 = lw+1
--        lr3 = krank*krank
--        lw = lw+lr3
--c
--        iind = lw+1
--        lind = n/4+1
--        lw = lw+1
--c
--        iindt = lw+1
--        lindt = m/4+1
--        lw = lw+1
--c
--c
--        call idz_id2svd0(m,krank,b,n,list,proj,u,v,s,ier,
--     1                   w(iwork),w(ip),w(it),w(ir),w(ir2),w(ir3),
--     2                   w(iind),w(iindt))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_id2svd0(m,krank,b,n,list,proj,u,v,s,ier,
--     1                         work,p,t,r,r2,r3,ind,indt)
--c
--c       routine idz_id2svd serves as a memory wrapper
--c       for the present routine (please see routine idz_id2svd
--c       for further documentation).
--c
--        implicit none
--c
--        character*1 jobz
--        integer m,n,krank,list(n),ind(n),indt(m),ifadjoint,
--     1          lwork,ldu,ldvt,ldr,info,j,k,ier
--        real*8 s(krank)
--        complex*16 b(m,krank),proj(krank,n-krank),p(krank,n),
--     1             r(krank,n),r2(krank,m),t(n,krank),r3(krank,krank),
--     2             u(m,krank),v(n,krank),work(8*krank**2+10*krank)
--c
--c
--c
--        ier = 0
--c
--c
--c
--c       Construct the projection matrix p from the ID.
--c
--        call idz_reconint(n,list,krank,proj,p)
--c
--c
--c
--c       Compute a pivoted QR decomposition of b.
--c
--        call idzr_qrpiv(m,krank,b,krank,ind,r)
--c
--c
--c       Extract r from the QR decomposition.
--c
--        call idz_rinqr(m,krank,b,krank,r)
--c
--c
--c       Rearrange r according to ind.
--c
--        call idz_rearr(krank,ind,krank,krank,r)
--c
--c
--c
--c       Take the adjoint of p to obtain t.
--c
--        call idz_matadj(krank,n,p,t)
--c
--c
--c       Compute a pivoted QR decomposition of t.
--c
--        call idzr_qrpiv(n,krank,t,krank,indt,r2)
--c
--c
--c       Extract r2 from the QR decomposition.
--c
--        call idz_rinqr(n,krank,t,krank,r2)
--c
--c
--c       Rearrange r2 according to indt.
--c
--        call idz_rearr(krank,indt,krank,krank,r2)
--c
--c
--c
--c       Multiply r and r2^* to obtain r3.
--c
--        call idz_matmulta(krank,krank,r,krank,r2,r3)
--c
--c
--c
--c       Use LAPACK to SVD r3.
--c
--        jobz = 'S'
--        ldr = krank
--        lwork = 8*krank**2+10*krank
--     1        - (krank**2+2*krank+3*krank**2+4*krank)
--        ldu = krank
--        ldvt = krank
--c
--        call zgesdd(jobz,krank,krank,r3,ldr,s,work,ldu,r,ldvt,
--     1              work(krank**2+2*krank+3*krank**2+4*krank+1),lwork,
--     2              work(krank**2+2*krank+1),work(krank**2+1),info)
--c
--        if(info .ne. 0) then
--          ier = info
--          return
--        endif
--c
--c
--c
--c       Multiply the u from r3 from the left by the q from b
--c       to obtain the u for a.
--c
--        do k = 1,krank
--c
--          do j = 1,krank
--            u(j,k) = work(j+krank*(k-1))
--          enddo ! j
--c
--          do j = krank+1,m
--            u(j,k) = 0
--          enddo ! j
--c
--        enddo ! k
--c
--        ifadjoint = 0
--        call idz_qmatmat(ifadjoint,m,krank,b,krank,krank,u,r2)
--c
--c
--c
--c       Take the adjoint of r to obtain r2.
--c
--        call idz_matadj(krank,krank,r,r2)
--c
--c
--c       Multiply the v from r3 from the left by the q from p^*
--c       to obtain the v for a.
--c
--        do k = 1,krank
--c
--          do j = 1,krank
--            v(j,k) = r2(j,k)
--          enddo ! j
--c
--          do j = krank+1,n
--            v(j,k) = 0
--          enddo ! j
--c
--        enddo ! k
--c
--        ifadjoint = 0
--        call idz_qmatmat(ifadjoint,n,krank,t,krank,krank,v,r2)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_matadj(m,n,a,aa)
--c
--c       Takes the adjoint of a to obtain aa.
--c
--c       input:
--c       m -- first dimension of a, and second dimension of aa
--c       n -- second dimension of a, and first dimension of aa
--c       a -- matrix whose adjoint is to be taken
--c
--c       output:
--c       aa -- adjoint of a
--c
--        implicit none
--        integer m,n,j,k
--        complex*16 a(m,n),aa(n,m)
--c
--c
--        do k = 1,n
--          do j = 1,m
--            aa(k,j) = conjg(a(j,k))
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_matmulta(l,m,a,n,b,c)
--c
--c       multiplies a and b^* to obtain c.
--c
--c       input:
--c       l -- first dimension of a and c
--c       m -- second dimension of a and b
--c       a -- leftmost matrix in the product c = a b^*
--c       n -- first dimension of b and second dimension of c
--c       b -- rightmost matrix in the product c = a b^*
--c
--c       output:
--c       c -- product of a and b^*
--c
--        implicit none
--        integer l,m,n,i,j,k
--        complex*16 a(l,m),b(n,m),c(l,n),sum
--c
--c
--        do i = 1,l
--          do k = 1,n
--c
--            sum = 0
--c
--            do j = 1,m
--              sum = sum+a(i,j)*conjg(b(k,j))
--            enddo ! j
--c
--            c(i,k) = sum
--c
--          enddo ! k
--        enddo ! i
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_rearr(krank,ind,m,n,a)
--c
--c       rearranges a according to ind obtained
--c       from routines idzr_qrpiv or idzp_qrpiv,
--c       assuming that a = q r, where q and r are from idzr_qrpiv
--c       or idzp_qrpiv.
--c
--c       input:
--c       krank -- rank obtained from routine idzp_qrpiv,
--c                or provided to routine idzr_qrpiv
--c       ind -- indexing array obtained from routine idzr_qrpiv
--c              or idzp_qrpiv
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       a -- matrix to be rearranged
--c
--c       output:
--c       a -- rearranged matrix
--c
--        implicit none
--        integer k,krank,m,n,j,ind(krank)
--        complex*16 cswap,a(m,n)
--c
--c
--        do k = krank,1,-1
--          do j = 1,m
--c
--            cswap = a(j,k)
--            a(j,k) = a(j,ind(k))
--            a(j,ind(k)) = cswap
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_rinqr(m,n,a,krank,r)
--c
--c       extracts R in the QR decomposition specified by the output a
--c       of the routine idzr_qrpiv or idzp_qrpiv.
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a and r
--c       a -- output of routine idzr_qrpiv or idzp_qrpiv
--c       krank -- rank output by routine idzp_qrpiv (or specified
--c                to routine idzr_qrpiv)
--c
--c       output:
--c       r -- triangular factor in the QR decomposition specified
--c            by the output a of the routine idzr_qrpiv or idzp_qrpiv
--c
--        implicit none
--        integer m,n,j,k,krank
--        complex*16 a(m,n),r(krank,n)
--c
--c
--c       Copy a into r and zero out the appropriate
--c       Householder vectors that are stored in one triangle of a.
--c
--        do k = 1,n
--          do j = 1,krank
--            r(j,k) = a(j,k)
--          enddo ! j
--        enddo ! k
--c
--        do k = 1,n
--          if(k .lt. krank) then
--            do j = k+1,krank
--              r(j,k) = 0
--            enddo ! j
--          endif
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idz_qrpiv.f b/scipy/linalg/src/id_dist/src/idz_qrpiv.f
-deleted file mode 100644
-index 3e7bcaf99..000000000
---- a/scipy/linalg/src/id_dist/src/idz_qrpiv.f
-+++ /dev/null
-@@ -1,898 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzp_qrpiv computes the pivoted QR decomposition
--c       of a matrix via Householder transformations,
--c       stopping at a specified precision of the decomposition.
--c
--c       routine idzr_qrpiv computes the pivoted QR decomposition
--c       of a matrix via Householder transformations,
--c       stopping at a specified rank of the decomposition.
--c
--c       routine idz_qmatvec applies to a single vector
--c       the Q matrix (or its adjoint) in the QR decomposition
--c       of a matrix, as described by the output of idzp_qrpiv or
--c       idzr_qrpiv. If you're concerned about efficiency and want
--c       to apply Q (or its adjoint) to multiple vectors,
--c       use idz_qmatmat instead.
--c
--c       routine idz_qmatmat applies
--c       to multiple vectors collected together
--c       as a matrix the Q matrix (or its adjoint)
--c       in the QR decomposition of a matrix, as described
--c       by the output of idzp_qrpiv. If you don't want to provide
--c       a work array and want to apply Q (or its adjoint)
--c       to a single vector, use idz_qmatvec instead.
--c
--c       routine idz_qinqr reconstructs the Q matrix
--c       in a QR decomposition from the data generated by idzp_qrpiv
--c       or idzr_qrpiv.
--c
--c       routine idz_permmult multiplies together a bunch
--c       of permutations.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idz_permmult(m,ind,n,indprod)
--c
--c       multiplies together the series of permutations in ind.
--c
--c       input:
--c       m -- length of ind
--c       ind(k) -- number of the slot with which to swap
--c                 the k^th slot
--c       n -- length of indprod and indprodinv
--c
--c       output:
--c       indprod -- product of the permutations in ind,
--c                  with the permutation swapping 1 and ind(1)
--c                  taken leftmost in the product,
--c                  that swapping 2 and ind(2) taken next leftmost,
--c                  ..., that swapping krank and ind(krank)
--c                  taken rightmost; indprod(k) is the number
--c                  of the slot with which to swap the k^th slot
--c                  in the product permutation
--c
--        implicit none
--        integer m,n,ind(m),indprod(n),k,iswap
--c
--c
--        do k = 1,n
--          indprod(k) = k
--        enddo ! k
--c
--        do k = m,1,-1
--c
--c         Swap indprod(k) and indprod(ind(k)).
--c
--          iswap = indprod(k)
--          indprod(k) = indprod(ind(k))
--          indprod(ind(k)) = iswap
--c
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_qinqr(m,n,a,krank,q)
--c
--c       constructs the matrix q from idzp_qrpiv or idzr_qrpiv
--c       (see the routine idzp_qrpiv or idzr_qrpiv
--c       for more information).
--c
--c       input:
--c       m -- first dimension of a; also, right now, q is m x m
--c       n -- second dimension of a
--c       a -- matrix output by idzp_qrpiv or idzr_qrpiv
--c            (and denoted the same there)
--c       krank -- numerical rank output by idzp_qrpiv or idzr_qrpiv
--c                (and denoted the same there)
--c
--c       output:
--c       q -- unitary matrix implicitly specified by the data in a
--c            from idzp_qrpiv or idzr_qrpiv
--c
--c       Note:
--c       Right now, this routine simply multiplies
--c       one after another the krank Householder matrices
--c       in the full QR decomposition of a,
--c       in order to obtain the complete m x m Q factor in the QR.
--c       This routine should instead use the following
--c       (more elaborate but more efficient) scheme
--c       to construct a q dimensioned q(krank,m); this scheme
--c       was introduced by Robert Schreiber and Charles Van Loan
--c       in "A Storage-Efficient _WY_ Representation
--c       for Products of Householder Transformations,"
--c       _SIAM Journal on Scientific and Statistical Computing_,
--c       Vol. 10, No. 1, pp. 53-57, January, 1989:
--c
--c       Theorem 1. Suppose that Q = _1_ + YTY^* is
--c       an m x m unitary matrix,
--c       where Y is an m x k matrix
--c       and T is a k x k upper triangular matrix.
--c       Suppose also that P = _1_ - 2 v v^* is
--c       a Householder matrix and Q_+ = QP,
--c       where v is an m x 1 real vector,
--c       normalized so that v^* v = 1.
--c       Then, Q_+ = _1_ + Y_+ T_+ Y_+^*,
--c       where Y_+ = (Y v) is the m x (k+1) matrix
--c       formed by adjoining v to the right of Y,
--c                 ( T   z )
--c       and T_+ = (       ) is
--c                 ( 0  -2 )
--c       the (k+1) x (k+1) upper triangular matrix
--c       formed by adjoining z to the right of T
--c       and the vector (0 ... 0 -2) with k zeroes below (T z),
--c       where z = -2 T Y^* v.
--c
--c       Now, suppose that A is a (rank-deficient) matrix
--c       whose complete QR decomposition has
--c       the blockwise partioned form
--c           ( Q_11 Q_12 ) ( R_11 R_12 )   ( Q_11 )
--c       A = (           ) (           ) = (      ) (R_11 R_12).
--c           ( Q_21 Q_22 ) (  0    0   )   ( Q_21 )
--c       Then, the only blocks of the orthogonal factor
--c       in the above QR decomposition of A that matter are
--c                                                        ( Q_11 )
--c       Q_11 and Q_21, _i.e._, only the block of columns (      )
--c                                                        ( Q_21 )
--c       interests us.
--c       Suppose in addition that Q_11 is a k x k matrix,
--c       Q_21 is an (m-k) x k matrix, and that
--c       ( Q_11 Q_12 )
--c       (           ) = _1_ + YTY^*, as in Theorem 1 above.
--c       ( Q_21 Q_22 )
--c       Then, Q_11 = _1_ + Y_1 T Y_1^*
--c       and Q_21 = Y_2 T Y_1^*,
--c       where Y_1 is the k x k matrix and Y_2 is the (m-k) x k matrix
--c                   ( Y_1 )
--c       so that Y = (     ).
--c                   ( Y_2 )
--c
--c       So, you can calculate T and Y via the above recursions,
--c       and then use these to compute the desired Q_11 and Q_21.
--c
--c
--        implicit none
--        integer m,n,krank,j,k,mm,ifrescal
--        real*8 scal
--        complex*16 a(m,n),q(m,m)
--c
--c
--c       Zero all of the entries of q.
--c
--        do k = 1,m
--          do j = 1,m
--            q(j,k) = 0
--          enddo ! j
--        enddo ! k
--c
--c
--c       Place 1's along the diagonal of q.
--c
--        do k = 1,m
--          q(k,k) = 1
--        enddo ! k
--c
--c
--c       Apply the krank Householder transformations stored in a.
--c
--        do k = krank,1,-1
--          do j = k,m
--            mm = m-k+1
--            ifrescal = 1
--            if(k .lt. m) call idz_houseapp(mm,a(k+1,k),q(k,j),
--     1                                     ifrescal,scal,q(k,j))
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_qmatvec(ifadjoint,m,n,a,krank,v)
--c
--c       applies to a single vector the Q matrix (or its adjoint)
--c       which the routine idzp_qrpiv or idzr_qrpiv has stored
--c       in a triangle of the matrix it produces (stored, incidentally,
--c       as data for applying a bunch of Householder reflections).
--c       Use the routine idz_qmatmat to apply the Q matrix
--c       (or its adjoint)
--c       to a bunch of vectors collected together as a matrix,
--c       if you're concerned about efficiency.
--c
--c       input:
--c       ifadjoint -- set to 0 for applying Q;
--c                    set to 1 for applying the adjoint of Q
--c       m -- first dimension of a and length of v
--c       n -- second dimension of a
--c       a -- data describing the qr decomposition of a matrix,
--c            as produced by idzp_qrpiv or idzr_qrpiv
--c       krank -- numerical rank
--c       v -- vector to which Q (or its adjoint) is to be applied
--c
--c       output:
--c       v -- vector to which Q (or its adjoint) has been applied
--c
--        implicit none
--        save
--        integer m,n,krank,k,ifrescal,mm,ifadjoint
--        real*8 scal
--        complex*16 a(m,n),v(m)
--c
--c
--        ifrescal = 1
--c
--c
--        if(ifadjoint .eq. 0) then
--c
--          do k = krank,1,-1
--            mm = m-k+1
--            if(k .lt. m) call idz_houseapp(mm,a(k+1,k),v(k),
--     1                                     ifrescal,scal,v(k))
--          enddo ! k
--c
--        endif
--c
--c
--        if(ifadjoint .eq. 1) then
--c
--          do k = 1,krank
--            mm = m-k+1
--            if(k .lt. m) call idz_houseapp(mm,a(k+1,k),v(k),
--     1                                     ifrescal,scal,v(k))
--          enddo ! k
--c
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_qmatmat(ifadjoint,m,n,a,krank,l,b,work)
--c
--c       applies to a bunch of vectors collected together as a matrix
--c       the Q matrix (or its adjoint) which the routine idzp_qrpiv
--c       or idzr_qrpiv has stored in a triangle of the matrix
--c       it produces (stored, incidentally, as data
--c       for applying a bunch of Householder reflections).
--c       Use the routine idz_qmatvec to apply the Q matrix
--c       (or its adjoint)
--c       to a single vector, if you'd rather not provide a work array.
--c
--c       input:
--c       ifadjoint -- set to 0 for applying Q;
--c                    set to 1 for applying the adjoint of Q
--c       m -- first dimension of both a and b
--c       n -- second dimension of a
--c       a -- data describing the qr decomposition of a matrix,
--c            as produced by idzp_qrpiv or idzr_qrpiv
--c       krank -- numerical rank
--c       l -- second dimension of b
--c       b -- matrix to which Q (or its adjoint) is to be applied
--c
--c       output:
--c       b -- matrix to which Q (or its adjoint) has been applied
--c
--c       work:
--c       work -- must be at least krank real*8 elements long
--c
--        implicit none
--        save
--        integer l,m,n,krank,j,k,ifrescal,mm,ifadjoint
--        real*8 work(krank)
--        complex*16 a(m,n),b(m,l)
--c
--c
--        if(ifadjoint .eq. 0) then
--c
--c
--c         Handle the first iteration, j = 1,
--c         calculating all scals (ifrescal = 1).
--c
--          ifrescal = 1
--c
--          j = 1
--c
--          do k = krank,1,-1
--            if(k .lt. m) then
--              mm = m-k+1
--              call idz_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
--     1                          work(k),b(k,j))
--            endif
--          enddo ! k
--c
--c
--          if(l .gt. 1) then
--c
--c           Handle the other iterations, j > 1,
--c           using the scals just computed (ifrescal = 0).
--c
--            ifrescal = 0
--c
--            do j = 2,l
--c
--              do k = krank,1,-1
--                if(k .lt. m) then
--                  mm = m-k+1
--                  call idz_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
--     1                              work(k),b(k,j))
--                endif
--              enddo ! k
--c
--            enddo ! j
--c
--          endif ! j .gt. 1
--c
--c
--        endif ! ifadjoint .eq. 0
--c
--c
--        if(ifadjoint .eq. 1) then
--c
--c
--c         Handle the first iteration, j = 1,
--c         calculating all scals (ifrescal = 1).
--c
--          ifrescal = 1
--c
--          j = 1
--c
--          do k = 1,krank
--            if(k .lt. m) then
--              mm = m-k+1
--              call idz_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
--     1                          work(k),b(k,j))
--            endif
--          enddo ! k
--c
--c
--          if(l .gt. 1) then
--c
--c           Handle the other iterations, j > 1,
--c           using the scals just computed (ifrescal = 0).
--c
--            ifrescal = 0
--c
--            do j = 2,l
--c
--              do k = 1,krank
--                if(k .lt. m) then
--                  mm = m-k+1
--                  call idz_houseapp(mm,a(k+1,k),b(k,j),ifrescal,
--     1                              work(k),b(k,j))
--                endif
--              enddo ! k
--c
--            enddo ! j
--c
--          endif ! j .gt. 1
--c
--c
--        endif ! ifadjoint .eq. 1
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzp_qrpiv(eps,m,n,a,krank,ind,ss)
--c
--c       computes the pivoted QR decomposition
--c       of the matrix input into a, using Householder transformations,
--c       _i.e._, transforms the matrix a from its input value in
--c       to the matrix out with entry
--c
--c                               m
--c       out(j,indprod(k))  =  Sigma  q(l,j) * in(l,k),
--c                              l=1
--c
--c       for all j = 1, ..., krank, and k = 1, ..., n,
--c
--c       where in = the a from before the routine runs,
--c       out = the a from after the routine runs,
--c       out(j,k) = 0 when j > k (so that out is triangular),
--c       q(1:m,1), ..., q(1:m,krank) are orthonormal,
--c       indprod is the product of the permutations given by ind,
--c       (as computable via the routine permmult,
--c       with the permutation swapping 1 and ind(1) taken leftmost
--c       in the product, that swapping 2 and ind(2) taken next leftmost,
--c       ..., that swapping krank and ind(krank) taken rightmost),
--c       and with the matrix out satisfying
--c
--c                   krank
--c       in(j,k)  =  Sigma  q(j,l) * out(l,indprod(k))  +  epsilon(j,k),
--c                    l=1
--c
--c       for all j = 1, ..., m, and k = 1, ..., n,
--c
--c       for some matrix epsilon such that
--c       the root-sum-square of the entries of epsilon
--c       <= the root-sum-square of the entries of in * eps.
--c       Well, technically, this routine outputs the Householder vectors
--c       (or, rather, their second through last entries)
--c       in the part of a that is supposed to get zeroed, that is,
--c       in a(j,k) with m >= j > k >= 1.
--c
--c       input:
--c       eps -- relative precision of the resulting QR decomposition
--c       m -- first dimension of a and q
--c       n -- second dimension of a
--c       a -- matrix whose QR decomposition gets computed
--c
--c       output:
--c       a -- triangular (R) factor in the QR decompositon
--c            of the matrix input into the same storage locations,
--c            with the Householder vectors stored in the part of a
--c            that would otherwise consist entirely of zeroes, that is,
--c            in a(j,k) with m >= j > k >= 1
--c       krank -- numerical rank
--c       ind(k) -- index of the k^th pivot vector;
--c                 the following code segment will correctly rearrange
--c                 the product b of q and the upper triangle of out
--c                 so that b matches the input matrix in
--c                 to relative precision eps:
--c
--c                 copy the non-rearranged product of q and out into b
--c                 set k to krank
--c                 [start of loop]
--c                   swap b(1:m,k) and b(1:m,ind(k))
--c                   decrement k by 1
--c                 if k > 0, then go to [start of loop]
--c
--c       work:
--c       ss -- must be at least n real*8 words long
--c
--c       _N.B._: This routine outputs the Householder vectors
--c       (or, rather, their second through last entries)
--c       in the part of a that is supposed to get zeroed, that is,
--c       in a(j,k) with m >= j > k >= 1.
--c
--c       reference:
--c       Golub and Van Loan, "Matrix Computations," 3rd edition,
--c            Johns Hopkins University Press, 1996, Chapter 5.
--c
--        implicit none
--        integer n,m,ind(n),krank,k,j,kpiv,mm,nupdate,ifrescal
--        real*8 ss(n),eps,ssmax,scal,ssmaxin,rswap,feps
--        complex*16 a(m,n),cswap
--c
--c
--        feps = .1d-16
--c
--c
--c       Compute the sum of squares of the entries in each column of a,
--c       the maximum of all such sums, and find the first pivot
--c       (column with the greatest such sum).
--c
--        ssmax = 0
--        kpiv = 1
--c
--        do k = 1,n
--c
--          ss(k) = 0
--          do j = 1,m
--            ss(k) = ss(k)+a(j,k)*conjg(a(j,k))
--          enddo ! j
--c
--          if(ss(k) .gt. ssmax) then
--            ssmax = ss(k)
--            kpiv = k
--          endif
--c
--        enddo ! k
--c
--        ssmaxin = ssmax
--c
--        nupdate = 0
--c
--c
--c       While ssmax > eps**2*ssmaxin, krank < m, and krank < n,
--c       do the following block of code,
--c       which ends at the statement labeled 2000.
--c
--        krank = 0
-- 1000   continue
--c
--        if(ssmax .le. eps**2*ssmaxin
--     1   .or. krank .ge. m .or. krank .ge. n) goto 2000
--        krank = krank+1
--c
--c
--          mm = m-krank+1
--c
--c
--c         Perform the pivoting.
--c
--          ind(krank) = kpiv
--c
--c         Swap a(1:m,krank) and a(1:m,kpiv).
--c
--          do j = 1,m
--            cswap = a(j,krank)
--            a(j,krank) = a(j,kpiv)
--            a(j,kpiv) = cswap
--          enddo ! j
--c
--c         Swap ss(krank) and ss(kpiv).
--c
--          rswap = ss(krank)
--          ss(krank) = ss(kpiv)
--          ss(kpiv) = rswap
--c
--c
--          if(krank .lt. m) then
--c
--c
--c           Compute the data for the Householder transformation
--c           which will zero a(krank+1,krank), ..., a(m,krank)
--c           when applied to a, replacing a(krank,krank)
--c           with the first entry of the result of the application
--c           of the Householder matrix to a(krank:m,krank),
--c           and storing entries 2 to mm of the Householder vector
--c           in a(krank+1,krank), ..., a(m,krank)
--c           (which otherwise would get zeroed upon application
--c           of the Householder transformation).
--c
--            call idz_house(mm,a(krank,krank),a(krank,krank),
--     1                     a(krank+1,krank),scal)
--            ifrescal = 0
--c
--c
--c           Apply the Householder transformation
--c           to the lower right submatrix of a
--c           with upper leftmost entry at position (krank,krank+1).
--c
--            if(krank .lt. n) then
--              do k = krank+1,n
--                call idz_houseapp(mm,a(krank+1,krank),a(krank,k),
--     1                            ifrescal,scal,a(krank,k))
--              enddo ! k
--            endif
--c
--c
--c           Update the sums-of-squares array ss.
--c
--            do k = krank,n
--              ss(k) = ss(k)-a(krank,k)*conjg(a(krank,k))
--            enddo ! k
--c
--c
--c           Find the pivot (column with the greatest sum of squares
--c           of its entries).
--c
--            ssmax = 0
--            kpiv = krank+1
--c
--            if(krank .lt. n) then
--c
--              do k = krank+1,n
--c
--                if(ss(k) .gt. ssmax) then
--                  ssmax = ss(k)
--                  kpiv = k
--                endif
--c
--              enddo ! k
--c
--            endif ! krank .lt. n
--c
--c
--c           Recompute the sums-of-squares and the pivot
--c           when ssmax first falls below
--c           sqrt((1000*feps)^2) * ssmaxin
--c           and when ssmax first falls below
--c           ((1000*feps)^2) * ssmaxin.
--c
--            if(
--     1       (ssmax .lt. sqrt((1000*feps)**2) * ssmaxin
--     2        .and. nupdate .eq. 0) .or.
--     3       (ssmax .lt. ((1000*feps)**2) * ssmaxin
--     4        .and. nupdate .eq. 1)
--     5      ) then
--c
--              nupdate = nupdate+1
--c
--              ssmax = 0
--              kpiv = krank+1
--c
--              if(krank .lt. n) then
--c
--                do k = krank+1,n
--c
--                  ss(k) = 0
--                  do j = krank+1,m
--                    ss(k) = ss(k)+a(j,k)*conjg(a(j,k))
--                  enddo ! j
--c
--                  if(ss(k) .gt. ssmax) then
--                    ssmax = ss(k)
--                    kpiv = k
--                  endif
--c
--                enddo ! k
--c
--              endif ! krank .lt. n
--c
--            endif
--c
--c
--          endif ! krank .lt. m
--c
--c
--        goto 1000
-- 2000   continue
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzr_qrpiv(m,n,a,krank,ind,ss)
--c
--c       computes the pivoted QR decomposition
--c       of the matrix input into a, using Householder transformations,
--c       _i.e._, transforms the matrix a from its input value in
--c       to the matrix out with entry
--c
--c                               m
--c       out(j,indprod(k))  =  Sigma  q(l,j) * in(l,k),
--c                              l=1
--c
--c       for all j = 1, ..., krank, and k = 1, ..., n,
--c
--c       where in = the a from before the routine runs,
--c       out = the a from after the routine runs,
--c       out(j,k) = 0 when j > k (so that out is triangular),
--c       q(1:m,1), ..., q(1:m,krank) are orthonormal,
--c       indprod is the product of the permutations given by ind,
--c       (as computable via the routine permmult,
--c       with the permutation swapping 1 and ind(1) taken leftmost
--c       in the product, that swapping 2 and ind(2) taken next leftmost,
--c       ..., that swapping krank and ind(krank) taken rightmost),
--c       and with the matrix out satisfying
--c
--c                  min(m,n,krank)
--c       in(j,k)  =     Sigma      q(j,l) * out(l,indprod(k))
--c                       l=1
--c
--c                +  epsilon(j,k),
--c
--c       for all j = 1, ..., m, and k = 1, ..., n,
--c
--c       for some matrix epsilon whose norm is (hopefully) minimized
--c       by the pivoting procedure.
--c       Well, technically, this routine outputs the Householder vectors
--c       (or, rather, their second through last entries)
--c       in the part of a that is supposed to get zeroed, that is,
--c       in a(j,k) with m >= j > k >= 1.
--c
--c       input:
--c       m -- first dimension of a and q
--c       n -- second dimension of a
--c       a -- matrix whose QR decomposition gets computed
--c       krank -- desired rank of the output matrix
--c                (please note that if krank > m or krank > n,
--c                then the rank of the output matrix will be
--c                less than krank)
--c
--c       output:
--c       a -- triangular (R) factor in the QR decompositon
--c            of the matrix input into the same storage locations,
--c            with the Householder vectors stored in the part of a
--c            that would otherwise consist entirely of zeroes, that is,
--c            in a(j,k) with m >= j > k >= 1
--c       ind(k) -- index of the k^th pivot vector;
--c                 the following code segment will correctly rearrange
--c                 the product b of q and the upper triangle of out
--c                 so that b matches the input matrix in
--c                 to relative precision eps:
--c
--c                 copy the non-rearranged product of q and out into b
--c                 set k to krank
--c                 [start of loop]
--c                   swap b(1:m,k) and b(1:m,ind(k))
--c                   decrement k by 1
--c                 if k > 0, then go to [start of loop]
--c
--c       work:
--c       ss -- must be at least n real*8 words long
--c
--c       _N.B._: This routine outputs the Householder vectors
--c       (or, rather, their second through last entries)
--c       in the part of a that is supposed to get zeroed, that is,
--c       in a(j,k) with m >= j > k >= 1.
--c
--c       reference:
--c       Golub and Van Loan, "Matrix Computations," 3rd edition,
--c            Johns Hopkins University Press, 1996, Chapter 5.
--c
--        implicit none
--        integer n,m,ind(n),krank,k,j,kpiv,mm,nupdate,ifrescal,
--     1          loops,loop
--        real*8 ss(n),ssmax,scal,ssmaxin,rswap,feps
--        complex*16 a(m,n),cswap
--c
--c
--        feps = .1d-16
--c
--c
--c       Compute the sum of squares of the entries in each column of a,
--c       the maximum of all such sums, and find the first pivot
--c       (column with the greatest such sum).
--c
--        ssmax = 0
--        kpiv = 1
--c
--        do k = 1,n
--c
--          ss(k) = 0
--          do j = 1,m
--            ss(k) = ss(k)+a(j,k)*conjg(a(j,k))
--          enddo ! j
--c
--          if(ss(k) .gt. ssmax) then
--            ssmax = ss(k)
--            kpiv = k
--          endif
--c
--        enddo ! k
--c
--        ssmaxin = ssmax
--c
--        nupdate = 0
--c
--c
--c       Set loops = min(krank,m,n).
--c
--        loops = krank
--        if(m .lt. loops) loops = m
--        if(n .lt. loops) loops = n
--c
--        do loop = 1,loops
--c
--c
--          mm = m-loop+1
--c
--c
--c         Perform the pivoting.
--c
--          ind(loop) = kpiv
--c
--c         Swap a(1:m,loop) and a(1:m,kpiv).
--c
--          do j = 1,m
--            cswap = a(j,loop)
--            a(j,loop) = a(j,kpiv)
--            a(j,kpiv) = cswap
--          enddo ! j
--c
--c         Swap ss(loop) and ss(kpiv).
--c
--          rswap = ss(loop)
--          ss(loop) = ss(kpiv)
--          ss(kpiv) = rswap
--c
--c
--          if(loop .lt. m) then
--c
--c
--c           Compute the data for the Householder transformation
--c           which will zero a(loop+1,loop), ..., a(m,loop)
--c           when applied to a, replacing a(loop,loop)
--c           with the first entry of the result of the application
--c           of the Householder matrix to a(loop:m,loop),
--c           and storing entries 2 to mm of the Householder vector
--c           in a(loop+1,loop), ..., a(m,loop)
--c           (which otherwise would get zeroed upon application
--c           of the Householder transformation).
--c
--            call idz_house(mm,a(loop,loop),a(loop,loop),
--     1                     a(loop+1,loop),scal)
--            ifrescal = 0
--c
--c
--c           Apply the Householder transformation
--c           to the lower right submatrix of a
--c           with upper leftmost entry at position (loop,loop+1).
--c
--            if(loop .lt. n) then
--              do k = loop+1,n
--                call idz_houseapp(mm,a(loop+1,loop),a(loop,k),
--     1                            ifrescal,scal,a(loop,k))
--              enddo ! k
--            endif
--c
--c
--c           Update the sums-of-squares array ss.
--c
--            do k = loop,n
--              ss(k) = ss(k)-a(loop,k)*conjg(a(loop,k))
--            enddo ! k
--c
--c
--c           Find the pivot (column with the greatest sum of squares
--c           of its entries).
--c
--            ssmax = 0
--            kpiv = loop+1
--c
--            if(loop .lt. n) then
--c
--              do k = loop+1,n
--c
--                if(ss(k) .gt. ssmax) then
--                  ssmax = ss(k)
--                  kpiv = k
--                endif
--c
--              enddo ! k
--c
--            endif ! loop .lt. n
--c
--c
--c           Recompute the sums-of-squares and the pivot
--c           when ssmax first falls below
--c           sqrt((1000*feps)^2) * ssmaxin
--c           and when ssmax first falls below
--c           ((1000*feps)^2) * ssmaxin.
--c
--            if(
--     1       (ssmax .lt. sqrt((1000*feps)**2) * ssmaxin
--     2        .and. nupdate .eq. 0) .or.
--     3       (ssmax .lt. ((1000*feps)**2) * ssmaxin
--     4        .and. nupdate .eq. 1)
--     5      ) then
--c
--              nupdate = nupdate+1
--c
--              ssmax = 0
--              kpiv = loop+1
--c
--              if(loop .lt. n) then
--c
--                do k = loop+1,n
--c
--                  ss(k) = 0
--                  do j = loop+1,m
--                    ss(k) = ss(k)+a(j,k)*conjg(a(j,k))
--                  enddo ! j
--c
--                  if(ss(k) .gt. ssmax) then
--                    ssmax = ss(k)
--                    kpiv = k
--                  endif
--c
--                enddo ! k
--c
--              endif ! loop .lt. n
--c
--            endif
--c
--c
--          endif ! loop .lt. m
--c
--c
--        enddo ! loop
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idz_sfft.f b/scipy/linalg/src/id_dist/src/idz_sfft.f
-deleted file mode 100644
-index c8dd9ab18..000000000
---- a/scipy/linalg/src/id_dist/src/idz_sfft.f
-+++ /dev/null
-@@ -1,210 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idz_sffti initializes routine idz_sfft.
--c
--c       routine idz_sfft rapidly computes a subset of the entries
--c       of the DFT of a vector, composed with permutation matrices
--c       both on input and on output.
--c
--c       routine idz_ldiv finds the greatest integer less than or equal
--c       to a specified integer, that is divisible by another (larger)
--c       specified integer.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idz_ldiv(l,n,m)
--c
--c       finds the greatest integer less than or equal to l
--c       that divides n.
--c
--c       input:
--c       l -- integer at least as great as m
--c       n -- integer divisible by m
--c
--c       output:
--c       m -- greatest integer less than or equal to l that divides n
--c
--        implicit none
--        integer n,l,m
--c
--c
--        m = l
--c
-- 1000   continue
--        if(m*(n/m) .eq. n) goto 2000
--c
--          m = m-1
--          goto 1000
--c
-- 2000   continue
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_sffti(l,ind,n,wsave)
--c
--c       initializes wsave for use with routine idz_sfft.
--c
--c       input:
--c       l -- number of entries in the output of idz_sfft to compute
--c       ind -- indices of the entries in the output of idz_sfft
--c              to compute
--c       n -- length of the vector to be transformed
--c
--c       output:
--c       wsave -- array needed by routine idz_sfft for processing
--c
--        implicit none
--        integer l,ind(l),n,nblock,ii,m,idivm,imodm,i,j,k
--        real*8 r1,twopi,fact
--        complex*16 wsave(2*l+15+3*n),ci,twopii
--c
--        ci = (0,1)
--        r1 = 1
--        twopi = 2*4*atan(r1)
--        twopii = twopi*ci
--c
--c
--c       Determine the block lengths for the FFTs.
--c
--        call idz_ldiv(l,n,nblock)
--        m = n/nblock
--c
--c
--c       Initialize wsave for use with routine zfftf.
--c
--        call zffti(nblock,wsave)
--c
--c
--c       Calculate the coefficients in the linear combinations
--c       needed for the direct portion of the calculation.
--c
--        fact = 1/sqrt(r1*n)
--c
--        ii = 2*l+15
--c
--        do j = 1,l
--c
--          i = ind(j)
--c
--          idivm = (i-1)/m
--          imodm = (i-1)-m*idivm
--c
--          do k = 1,m
--            wsave(ii+m*(j-1)+k) = exp(-twopii*imodm*(k-1)/(r1*m))
--     1       * exp(-twopii*(k-1)*idivm/(r1*n)) * fact
--          enddo ! k
--c
--        enddo ! j
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_sfft(l,ind,n,wsave,v)
--c
--c       computes a subset of the entries of the DFT of v,
--c       composed with permutation matrices both on input and on output,
--c       via a two-stage procedure (routine zfftf2 is supposed
--c       to calculate the full vector from which idz_sfft returns
--c       a subset of the entries, when zfftf2 has the same parameter
--c       nblock as in the present routine).
--c
--c       input:
--c       l -- number of entries in the output to compute
--c       ind -- indices of the entries of the output to compute
--c       n -- length of v
--c       v -- vector to be transformed
--c       wsave -- processing array initialized by routine idz_sffti
--c
--c       output:
--c       v -- entries indexed by ind are given their appropriate
--c            transformed values
--c
--c       _N.B._: The user has to boost the memory allocations
--c               for wsave (and change iii accordingly) if s/he wishes
--c               to use strange sizes of n; it's best to stick to powers
--c               of 2.
--c
--c       references:
--c       Sorensen and Burrus, "Efficient computation of the DFT with
--c            only a subset of input or output points,"
--c            IEEE Transactions on Signal Processing, 41 (3): 1184-1200,
--c            1993.
--c       Woolfe, Liberty, Rokhlin, Tygert, "A fast randomized algorithm
--c            for the approximation of matrices," Applied and
--c            Computational Harmonic Analysis, 25 (3): 335-366, 2008;
--c            Section 3.3.
--c
--        implicit none
--        integer n,m,l,k,j,ind(l),i,idivm,nblock,ii,iii
--        real*8 r1,twopi
--        complex*16 v(n),wsave(2*l+15+3*n),ci,sum
--c
--        ci = (0,1)
--        r1 = 1
--        twopi = 2*4*atan(r1)
--c
--c
--c       Determine the block lengths for the FFTs.
--c
--        call idz_ldiv(l,n,nblock)
--c
--c
--        m = n/nblock
--c
--c
--c       FFT each block of length nblock of v.
--c
--        do k = 1,m
--          call zfftf(nblock,v(nblock*(k-1)+1),wsave)
--        enddo ! k
--c
--c
--c       Transpose v to obtain wsave(2*l+15+2*n+1 : 2*l+15+3*n).
--c
--        iii = 2*l+15+2*n
--c
--        do k = 1,m
--          do j = 1,nblock
--            wsave(iii+m*(j-1)+k) = v(nblock*(k-1)+j)
--          enddo ! j
--        enddo ! k
--c
--c
--c       Directly calculate the desired entries of v.
--c
--        ii = 2*l+15
--        iii = 2*l+15+2*n
--c
--        do j = 1,l
--c
--          i = ind(j)
--c
--          idivm = (i-1)/m
--c
--          sum = 0
--c
--          do k = 1,m
--            sum = sum + wsave(ii+m*(j-1)+k) * wsave(iii+m*idivm+k)
--          enddo ! k
--c
--          v(i) = sum
--c
--        enddo ! j
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idz_snorm.f b/scipy/linalg/src/id_dist/src/idz_snorm.f
-deleted file mode 100644
-index 9fe713d47..000000000
---- a/scipy/linalg/src/id_dist/src/idz_snorm.f
-+++ /dev/null
-@@ -1,407 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idz_snorm estimates the spectral norm
--c       of a matrix specified by routines for applying the matrix
--c       and its adjoint to arbitrary vectors. This routine uses
--c       the power method with a random starting vector.
--c
--c       routine idz_diffsnorm estimates the spectral norm
--c       of the difference between two matrices specified by routines
--c       for applying the matrices and their adjoints
--c       to arbitrary vectors. This routine uses
--c       the power method with a random starting vector.
--c
--c       routine idz_enorm calculates the Euclidean norm of a vector.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idz_snorm(m,n,matveca,p1a,p2a,p3a,p4a,
--     1                       matvec,p1,p2,p3,p4,its,snorm,v,u)
--c
--c       estimates the spectral norm of a matrix a specified
--c       by a routine matvec for applying a to an arbitrary vector,
--c       and by a routine matveca for applying a^*
--c       to an arbitrary vector. This routine uses the power method
--c       with a random starting vector.
--c
--c       input:
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       matveca -- routine which applies the adjoint of a
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matveca(m,x,n,y,p1a,p2a,p3a,p4a),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the adjoint of a
--c                  is to be applied,
--c                  n is the length of y,
--c                  y is the product of the adjoint of a and x,
--c                  and p1a, p2a, p3a, and p4a are user-specified
--c                  parameters
--c       p1a -- parameter to be passed to routine matveca
--c       p2a -- parameter to be passed to routine matveca
--c       p3a -- parameter to be passed to routine matveca
--c       p4a -- parameter to be passed to routine matveca
--c       matvec -- routine which applies the matrix a
--c                 to an arbitrary vector; this routine must have
--c                 a calling sequence of the form
--c
--c                 matvec(n,x,m,y,p1,p2,p3,p4),
--c
--c                 where n is the length of x,
--c                 x is the vector to which a is to be applied,
--c                 m is the length of y,
--c                 y is the product of a and x,
--c                 and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvec
--c       p2 -- parameter to be passed to routine matvec
--c       p3 -- parameter to be passed to routine matvec
--c       p4 -- parameter to be passed to routine matvec
--c       its -- number of iterations of the power method to conduct
--c
--c       output:
--c       snorm -- estimate of the spectral norm of a
--c       v -- estimate of a normalized right singular vector
--c            corresponding to the greatest singular value of a
--c
--c       work:
--c       u -- must be at least m complex*16 elements long
--c
--c       reference:
--c       Kuczynski and Wozniakowski, "Estimating the largest eigenvalue
--c            by the power and Lanczos algorithms with a random start,"
--c            SIAM Journal on Matrix Analysis and Applications,
--c            13 (4): 1992, 1094-1122.
--c
--        implicit none
--        integer m,n,its,it,n2,k
--        real*8 snorm,enorm
--        complex*16 p1a,p2a,p3a,p4a,p1,p2,p3,p4,u(m),v(n)
--        external matveca,matvec
--c
--c
--c       Fill the real and imaginary parts of each entry
--c       of the initial vector v with i.i.d. random variables
--c       drawn uniformly from [-1,1].
--c
--        n2 = 2*n
--        call id_srand(n2,v)
--c
--        do k = 1,n
--          v(k) = 2*v(k)-1
--        enddo ! k
--c
--c
--c       Normalize v.
--c
--        call idz_enorm(n,v,enorm)
--c
--        do k = 1,n
--          v(k) = v(k)/enorm
--        enddo ! k
--c
--c
--        do it = 1,its
--c
--c         Apply a to v, obtaining u.
--c
--          call matvec(n,v,m,u,p1,p2,p3,p4)
--c
--c         Apply a^* to u, obtaining v.
--c
--          call matveca(m,u,n,v,p1a,p2a,p3a,p4a)
--c
--c         Normalize v.
--c
--          call idz_enorm(n,v,snorm)
--c
--          if(snorm .ne. 0) then
--c
--            do k = 1,n
--              v(k) = v(k)/snorm
--            enddo ! k
--c
--          endif
--c
--          snorm = sqrt(snorm)
--c
--        enddo ! it
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_enorm(n,v,enorm)
--c
--c       computes the Euclidean norm of v, the square root
--c       of the sum of the squares of the absolute values
--c       of the entries of v.
--c
--c       input:
--c       n -- length of v
--c       v -- vector whose Euclidean norm is to be calculated
--c
--c       output:
--c       enorm -- Euclidean norm of v
--c
--        implicit none
--        integer n,k
--        real*8 enorm
--        complex*16 v(n)
--c
--c
--        enorm = 0
--c
--        do k = 1,n
--          enorm = enorm+v(k)*conjg(v(k))
--        enddo ! k
--c
--        enorm = sqrt(enorm)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_diffsnorm(m,n,matveca,p1a,p2a,p3a,p4a,
--     1                           matveca2,p1a2,p2a2,p3a2,p4a2,
--     2                           matvec,p1,p2,p3,p4,
--     3                           matvec2,p12,p22,p32,p42,its,snorm,w)
--c
--c       estimates the spectral norm of the difference between matrices
--c       a and a2, where a is specified by routines matvec and matveca
--c       for applying a and a^* to arbitrary vectors,
--c       and a2 is specified by routines matvec2 and matveca2
--c       for applying a2 and (a2)^* to arbitrary vectors.
--c       This routine uses the power method
--c       with a random starting vector.
--c
--c       input:
--c       m -- number of rows in a, as well as the number of rows in a2
--c       n -- number of columns in a, as well as the number of columns
--c            in a2
--c       matveca -- routine which applies the adjoint of a
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matveca(m,x,n,y,p1a,p2a,p3a,p4a),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the adjoint of a
--c                  is to be applied,
--c                  n is the length of y,
--c                  y is the product of the adjoint of a and x,
--c                  and p1a, p2a, p3a, and p4a are user-specified
--c                  parameters
--c       p1a -- parameter to be passed to routine matveca
--c       p2a -- parameter to be passed to routine matveca
--c       p3a -- parameter to be passed to routine matveca
--c       p4a -- parameter to be passed to routine matveca
--c       matveca2 -- routine which applies the adjoint of a2
--c                   to an arbitrary vector; this routine must have
--c                   a calling sequence of the form
--c
--c                   matveca2(m,x,n,y,p1a2,p2a2,p3a2,p4a2),
--c
--c                   where m is the length of x,
--c                   x is the vector to which the adjoint of a2
--c                   is to be applied,
--c                   n is the length of y,
--c                   y is the product of the adjoint of a2 and x,
--c                   and p1a2, p2a2, p3a2, and p4a2 are user-specified
--c                   parameters
--c       p1a2 -- parameter to be passed to routine matveca2
--c       p2a2 -- parameter to be passed to routine matveca2
--c       p3a2 -- parameter to be passed to routine matveca2
--c       p4a2 -- parameter to be passed to routine matveca2
--c       matvec -- routine which applies the matrix a
--c                 to an arbitrary vector; this routine must have
--c                 a calling sequence of the form
--c
--c                 matvec(n,x,m,y,p1,p2,p3,p4),
--c
--c                 where n is the length of x,
--c                 x is the vector to which a is to be applied,
--c                 m is the length of y,
--c                 y is the product of a and x,
--c                 and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvec
--c       p2 -- parameter to be passed to routine matvec
--c       p3 -- parameter to be passed to routine matvec
--c       p4 -- parameter to be passed to routine matvec
--c       matvec2 -- routine which applies the matrix a2
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matvec2(n,x,m,y,p12,p22,p32,p42),
--c
--c                  where n is the length of x,
--c                  x is the vector to which a2 is to be applied,
--c                  m is the length of y,
--c                  y is the product of a2 and x, and
--c                  p12, p22, p32, and p42 are user-specified parameters
--c       p12 -- parameter to be passed to routine matvec2
--c       p22 -- parameter to be passed to routine matvec2
--c       p32 -- parameter to be passed to routine matvec2
--c       p42 -- parameter to be passed to routine matvec2
--c       its -- number of iterations of the power method to conduct
--c
--c       output:
--c       snorm -- estimate of the spectral norm of a-a2
--c
--c       work:
--c       w -- must be at least 3*m+3*n complex*16 elements long
--c
--c       reference:
--c       Kuczynski and Wozniakowski, "Estimating the largest eigenvalue
--c            by the power and Lanczos algorithms with a random start,"
--c            SIAM Journal on Matrix Analysis and Applications,
--c            13 (4): 1992, 1094-1122.
--c
--        implicit none
--        integer m,n,its,lw,iu,lu,iu1,lu1,iu2,lu2,
--     1          iv,lv,iv1,lv1,iv2,lv2
--        real*8 snorm
--        complex*16 p1a,p2a,p3a,p4a,p1a2,p2a2,p3a2,p4a2,
--     1             p1,p2,p3,p4,p12,p22,p32,p42,w(3*m+3*n)
--        external matveca,matvec,matveca2,matvec2
--c
--c
--c       Allocate memory in w.
--c
--        lw = 0
--c
--        iu = lw+1
--        lu = m
--        lw = lw+lu
--c
--        iu1 = lw+1
--        lu1 = m
--        lw = lw+lu1
--c
--        iu2 = lw+1
--        lu2 = m
--        lw = lw+lu2
--c
--        iv = lw+1
--        lv = n
--        lw = lw+1
--c
--        iv1 = lw+1
--        lv1 = n
--        lw = lw+lv1
--c
--        iv2 = lw+1
--        lv2 = n
--        lw = lw+lv2
--c
--c
--        call idz_diffsnorm0(m,n,matveca,p1a,p2a,p3a,p4a,
--     1                      matveca2,p1a2,p2a2,p3a2,p4a2,
--     2                      matvec,p1,p2,p3,p4,
--     3                      matvec2,p12,p22,p32,p42,
--     4                      its,snorm,w(iu),w(iu1),w(iu2),
--     5                      w(iv),w(iv1),w(iv2))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_diffsnorm0(m,n,matveca,p1a,p2a,p3a,p4a,
--     1                            matveca2,p1a2,p2a2,p3a2,p4a2,
--     2                            matvec,p1,p2,p3,p4,
--     3                            matvec2,p12,p22,p32,p42,
--     4                            its,snorm,u,u1,u2,v,v1,v2)
--c
--c       routine idz_diffsnorm serves as a memory wrapper
--c       for the present routine. (Please see routine idz_diffsnorm
--c       for further documentation.)
--c
--        implicit none
--        integer m,n,its,it,n2,k
--        real*8 snorm,enorm
--        complex*16 p1a,p2a,p3a,p4a,p1a2,p2a2,p3a2,p4a2,
--     1             p1,p2,p3,p4,p12,p22,p32,p42,u(m),u1(m),u2(m),
--     2             v(n),v1(n),v2(n)
--        external matveca,matvec,matveca2,matvec2
--c
--c
--c       Fill the real and imaginary parts of each entry
--c       of the initial vector v with i.i.d. random variables
--c       drawn uniformly from [-1,1].
--c
--        n2 = 2*n
--        call id_srand(n2,v)
--c
--        do k = 1,n
--          v(k) = 2*v(k)-1
--        enddo ! k
--c
--c
--c       Normalize v.
--c
--        call idz_enorm(n,v,enorm)
--c
--        do k = 1,n
--          v(k) = v(k)/enorm
--        enddo ! k
--c
--c
--        do it = 1,its
--c
--c         Apply a and a2 to v, obtaining u1 and u2.
--c
--          call matvec(n,v,m,u1,p1,p2,p3,p4)
--          call matvec2(n,v,m,u2,p12,p22,p32,p42)
--c
--c         Form u = u1-u2.
--c
--          do k = 1,m
--            u(k) = u1(k)-u2(k)
--          enddo ! k
--c
--c         Apply a^* and (a2)^* to u, obtaining v1 and v2.
--c
--          call matveca(m,u,n,v1,p1a,p2a,p3a,p4a)
--          call matveca2(m,u,n,v2,p1a2,p2a2,p3a2,p4a2)
--c
--c         Form v = v1-v2.
--c
--          do k = 1,n
--            v(k) = v1(k)-v2(k)
--          enddo ! k
--c
--c         Normalize v.
--c
--          call idz_enorm(n,v,snorm)
--c
--          if(snorm .gt. 0) then
--c
--            do k = 1,n
--              v(k) = v(k)/snorm
--            enddo ! k
--c
--          endif
--c
--          snorm = sqrt(snorm)
--c
--        enddo ! it
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idz_svd.f b/scipy/linalg/src/id_dist/src/idz_svd.f
-deleted file mode 100644
-index e14cf66a0..000000000
---- a/scipy/linalg/src/id_dist/src/idz_svd.f
-+++ /dev/null
-@@ -1,438 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzr_svd computes an approximation of specified rank
--c       to a given matrix, in the usual SVD form U S V^*,
--c       where U has orthonormal columns, V has orthonormal columns,
--c       and S is diagonal.
--c
--c       routine idzp_svd computes an approximation of specified
--c       precision to a given matrix, in the usual SVD form U S V^*,
--c       where U has orthonormal columns, V has orthonormal columns,
--c       and S is diagonal.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idzr_svd(m,n,a,krank,u,v,s,ier,r)
--c
--c       constructs a rank-krank SVD  u diag(s) v^*  approximating a,
--c       where u is an m x krank matrix whose columns are orthonormal,
--c       v is an n x krank matrix whose columns are orthonormal,
--c       and diag(s) is a diagonal krank x krank matrix whose entries
--c       are all nonnegative. This routine combines a QR code
--c       (which is based on plane/Householder reflections)
--c       with the LAPACK routine zgesdd.
--c
--c       input:
--c       m -- first dimension of a and u
--c       n -- second dimension of a, and first dimension of v
--c       a -- matrix to be SVD'd
--c       krank -- desired rank of the approximation to a
--c
--c       output:
--c       u -- left singular vectors of a corresponding
--c            to the k greatest singular values of a
--c       v -- right singular vectors of a corresponding
--c            to the k greatest singular values of a
--c       s -- k greatest singular values of a
--c       ier -- 0 when the routine terminates successfully;
--c              nonzero when the routine encounters an error
--c
--c       work:
--c       r -- must be at least
--c            (krank+2)*n+8*min(m,n)+6*krank**2+8*krank
--c            complex*16 elements long
--c
--c       _N.B._: This routine destroys a. Also, please beware that
--c               the source code for this routine could be clearer.
--c
--        implicit none
--        character*1 jobz
--        integer m,n,k,krank,ifadjoint,ldr,ldu,ldvadj,lwork,
--     1          info,j,ier,io
--        real*8 s(krank)
--        complex*16 a(m,n),u(m,krank),v(n*krank),r(*)
--c
--c
--        io = 8*min(m,n)
--c
--c
--        ier = 0
--c
--c
--c       Compute a pivoted QR decomposition of a.
--c
--        call idzr_qrpiv(m,n,a,krank,r,r(io+1))
--c
--c
--c       Extract R from the QR decomposition.
--c
--        call idz_retriever(m,n,a,krank,r(io+1))
--c
--c
--c       Rearrange R according to ind.
--c
--        call idz_permuter(krank,r,krank,n,r(io+1))
--c
--c
--c       Use LAPACK to SVD r,
--c       storing the krank (krank x 1) left singular vectors
--c       in r(io+krank*n+1 : io+krank*n+krank*krank).
--c
--        jobz = 'S'
--        ldr = krank
--        lwork = 2*(krank**2+2*krank+n)
--        ldu = krank
--        ldvadj = krank
--c
--        call zgesdd(jobz,krank,n,r(io+1),ldr,s,r(io+krank*n+1),ldu,
--     1              v,ldvadj,r(io+krank*n+krank*krank+1),lwork,
--     2              r(io+krank*n+krank*krank+lwork+1),r,info)
--c
--        if(info .ne. 0) then
--          ier = info
--          return
--        endif
--c
--c
--c       Multiply the U from R from the left by Q to obtain the U
--c       for A.
--c
--        do k = 1,krank
--c
--          do j = 1,krank
--            u(j,k) = r(io+krank*n+j+krank*(k-1))
--          enddo ! j
--c
--          do j = krank+1,m
--            u(j,k) = 0
--          enddo ! j
--c
--        enddo ! k
--c
--        ifadjoint = 0
--        call idz_qmatmat(ifadjoint,m,n,a,krank,krank,u,r)
--c
--c
--c       Take the adjoint of v to obtain r.
--c
--        call idz_adjer(krank,n,v,r)
--c
--c
--c       Copy r into v.
--c
--        do k = 1,n*krank
--          v(k) = r(k)
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzp_svd(lw,eps,m,n,a,krank,iu,iv,is,w,ier)
--c
--c       constructs a rank-krank SVD  U Sigma V^*  approximating a
--c       to precision eps, where U is an m x krank matrix whose
--c       columns are orthonormal, V is an n x krank matrix whose
--c       columns are orthonormal, and Sigma is a diagonal krank x krank
--c       matrix whose entries are all nonnegative.
--c       The entries of U are stored in w, starting at w(iu);
--c       the entries of V are stored in w, starting at w(iv).
--c       The diagonal entries of Sigma are stored in w,
--c       starting at w(is). This routine combines a QR code
--c       (which is based on plane/Householder reflections)
--c       with the LAPACK routine zgesdd.
--c
--c       input:
--c       lw -- maximum usable length of w (in complex*16 elements)
--c       eps -- precision to which the SVD approximates a
--c       m -- first dimension of a and u
--c       n -- second dimension of a, and first dimension of v
--c       a -- matrix to be SVD'd
--c
--c       output:
--c       krank -- rank of the approximation to a
--c       iu -- index in w of the first entry of the matrix
--c             of orthonormal left singular vectors of a
--c       iv -- index in w of the first entry of the matrix
--c             of orthonormal right singular vectors of a
--c       is -- index in w of the first entry of the array
--c             of singular values of a; the singular values are stored
--c             as complex*16 numbers whose imaginary parts are zeros
--c       w -- array containing the singular values and singular vectors
--c            of a; w doubles as a work array, and so must be at least
--c            (krank+1)*(m+2*n+9)+8*min(m,n)+6*krank**2
--c            complex*16 elements long, where krank is the rank
--c            output by the present routine
--c       ier -- 0 when the routine terminates successfully;
--c              -1000 when lw is too small;
--c              other nonzero values when zgesdd bombs
--c
--c       _N.B._: This routine destroys a. Also, please beware that
--c               the source code for this routine could be clearer.
--c               w must be at least
--c               (krank+1)*(m+2*n+9)+8*min(m,n)+6*krank**2
--c               complex*16 elements long, where krank is the rank
--c               output by the present routine.
--c
--        implicit none
--        character*1 jobz
--        integer m,n,k,krank,ifadjoint,ldr,ldu,ldvadj,lwork,
--     1          info,j,ier,io,iu,iv,is,ivi,isi,lu,lv,ls,lw
--        real*8 eps
--        complex*16 a(m,n),w(*)
--c
--c
--        io = 8*min(m,n)
--c
--c
--        ier = 0
--c
--c
--c       Compute a pivoted QR decomposition of a.
--c
--        call idzp_qrpiv(eps,m,n,a,krank,w,w(io+1))
--c
--c
--        if(krank .gt. 0) then
--c
--c
--c         Extract R from the QR decomposition.
--c
--          call idz_retriever(m,n,a,krank,w(io+1))
--c
--c
--c         Rearrange R according to ind.
--c
--          call idz_permuter(krank,w,krank,n,w(io+1))
--c
--c
--c         Use LAPACK to SVD R,
--c         storing the krank (krank x 1) left singular vectors
--c         in w(io+krank*n+1 : io+krank*n+krank*krank).
--c
--          jobz = 'S'
--          ldr = krank
--          lwork = 2*(krank**2+2*krank+n)
--          ldu = krank
--          ldvadj = krank
--c
--          ivi = io+krank*n+krank*krank+lwork+3*krank**2+4*krank+1
--          lv = n*krank
--c
--          isi = ivi+lv
--          ls = krank
--c
--          if(lw .lt. isi+ls+m*krank-1) then
--            ier = -1000
--            return
--          endif
--c
--          call zgesdd(jobz,krank,n,w(io+1),ldr,w(isi),w(io+krank*n+1),
--     1                ldu,w(ivi),ldvadj,w(io+krank*n+krank*krank+1),
--     2                lwork,w(io+krank*n+krank*krank+lwork+1),w,info)
--c
--          if(info .ne. 0) then
--            ier = info
--            return
--          endif
--c
--c
--c         Take the adjoint of w(ivi:ivi+lv-1) to obtain V.
--c
--          iv = 1
--          call idz_adjer(krank,n,w(ivi),w(iv))
--c
--c
--c         Copy w(isi:isi+ls/2) into w(is:is+ls-1).
--c
--          is = iv+lv
--c
--          call idz_realcomp(ls,w(isi),w(is))
--c
--c
--c         Multiply the U from R from the left by Q to obtain the U
--c         for A.
--c
--          iu = is+ls
--          lu = m*krank
--c
--          do k = 1,krank
--c
--            do j = 1,krank
--              w(iu-1+j+krank*(k-1)) = w(io+krank*n+j+krank*(k-1))
--            enddo ! j
--c
--          enddo ! k
--c
--          do k = krank,1,-1
--c
--            do j = m,krank+1,-1
--              w(iu-1+j+m*(k-1)) = 0
--            enddo ! j
--c
--            do j = krank,1,-1
--              w(iu-1+j+m*(k-1)) = w(iu-1+j+krank*(k-1))
--            enddo ! j
--c
--          enddo ! k
--c
--          ifadjoint = 0
--          call idz_qmatmat(ifadjoint,m,n,a,krank,krank,w(iu),
--     1                     w(iu+lu+1))
--c
--c
--        endif ! krank .gt. 0
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_realcomp(n,a,b)
--c
--c       copies the real*8 array a into the complex*16 array b.
--c
--c       input:
--c       n -- length of a and b
--c       a -- real*8 array to be copied into b
--c
--c       output:
--c       b -- complex*16 copy of a
--c
--        integer n,k
--        real*8 a(n)
--        complex*16 b(n)
--c
--c
--        do k = 1,n
--          b(k) = a(k)
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_permuter(krank,ind,m,n,a)
--c
--c       permutes the columns of a according to ind obtained
--c       from routine idzr_qrpiv or idzp_qrpiv, assuming that
--c       a = q r from idzr_qrpiv or idzp_qrpiv.
--c
--c       input:
--c       krank -- rank specified to routine idzr_qrpiv
--c                or obtained from routine idzp_qrpiv
--c       ind -- indexing array obtained from routine idzr_qrpiv
--c              or idzp_qrpiv
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       a -- matrix to be rearranged
--c
--c       output:
--c       a -- rearranged matrix
--c
--        implicit none
--        integer k,krank,m,n,j,ind(krank)
--        complex*16 cswap,a(m,n)
--c
--c
--        do k = krank,1,-1
--          do j = 1,m
--c
--            cswap = a(j,k)
--            a(j,k) = a(j,ind(k))
--            a(j,ind(k)) = cswap
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_retriever(m,n,a,krank,r)
--c
--c       extracts R in the QR decomposition specified by the output a
--c       of the routine idzr_qrpiv or idzp_qrpiv
--c
--c       input:
--c       m -- first dimension of a
--c       n -- second dimension of a and r
--c       a -- output of routine idzr_qrpiv or idzp_qrpiv
--c       krank -- rank specified to routine idzr_qrpiv,
--c                or output by routine idzp_qrpiv
--c
--c       output:
--c       r -- triangular factor in the QR decomposition specified
--c            by the output a of the routine idzr_qrpiv or idzp_qrpiv
--c
--        implicit none
--        integer m,n,j,k,krank
--        complex*16 a(m,n),r(krank,n)
--c
--c
--c       Copy a into r and zero out the appropriate
--c       Householder vectors that are stored in one triangle of a.
--c
--        do k = 1,n
--          do j = 1,krank
--            r(j,k) = a(j,k)
--          enddo ! j
--        enddo ! k
--c
--        do k = 1,n
--          if(k .lt. krank) then
--            do j = k+1,krank
--              r(j,k) = 0
--            enddo ! j
--          endif
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_adjer(m,n,a,aa)
--c
--c       forms the adjoint aa of a.
--c
--c       input:
--c       m -- first dimension of a and second dimension of aa
--c       n -- second dimension of a and first dimension of aa
--c       a -- matrix whose adjoint is to be taken
--c
--c       output:
--c       aa -- adjoint of a
--c
--        implicit none
--        integer m,n,j,k
--        complex*16 a(m,n),aa(n,m)
--c
--c
--        do k = 1,n
--          do j = 1,m
--            aa(k,j) = conjg(a(j,k))
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idzp_aid.f b/scipy/linalg/src/id_dist/src/idzp_aid.f
-deleted file mode 100644
-index 784b40cde..000000000
---- a/scipy/linalg/src/id_dist/src/idzp_aid.f
-+++ /dev/null
-@@ -1,390 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzp_aid computes the ID, to a specified precision,
--c       of an arbitrary matrix. This routine is randomized.
--c
--c       routine idz_estrank estimates the numerical rank,
--c       to a specified precision, of an arbitrary matrix.
--c       This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idzp_aid(eps,m,n,a,work,krank,list,proj)
--c
--c       computes the ID of the matrix a, i.e., lists in list
--c       the indices of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                        krank
--c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
--c                         l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon dimensioned epsilon(m,n-krank)
--c       such that the greatest singular value of epsilon
--c       <= the greatest singular value of a * eps.
--c
--c       input:
--c       eps -- precision to which the ID is to be computed
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       a -- matrix to be decomposed; the present routine does not
--c            alter a
--c       work -- initialization array that has been constructed
--c               by routine idz_frmi
--c
--c       output:
--c       krank -- numerical rank of a to precision eps
--c       list -- indices of the columns in the ID
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns
--c               in the original matrix being ID'd;
--c               proj doubles as a work array in the present routine, so
--c               proj must be at least n*(2*n2+1)+n2+1 complex*16
--c               elements long, where n2 is the greatest integer
--c               less than or equal to m, such that n2 is
--c               a positive integer power of two.
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c               proj must be at least n*(2*n2+1)+n2+1 complex*16
--c               elements long, where n2 is the greatest integer
--c               less than or equal to m, such that n2 is
--c               a positive integer power of two.
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,n,list(n),krank,kranki,n2
--        real*8 eps
--        complex*16 a(m,n),proj(*),work(17*m+70)
--c
--c
--c       Allocate memory in proj.
--c
--        n2 = work(2)
--c
--c
--c       Find the rank of a.
--c
--        call idz_estrank(eps,m,n,a,work,kranki,proj)
--c
--c
--        if(kranki .eq. 0) call idzp_aid0(eps,m,n,a,krank,list,proj,
--     1                                   proj(m*n+1))
--c
--        if(kranki .ne. 0) call idzp_aid1(eps,n2,n,kranki,proj,
--     1                                   krank,list,proj(n2*n+1))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzp_aid0(eps,m,n,a,krank,list,proj,rnorms)
--c
--c       uses routine idzp_id to ID a without modifying its entries
--c       (in contrast to the usual behavior of idzp_id).
--c
--c       input:
--c       eps -- precision of the decomposition to be constructed
--c       m -- first dimension of a
--c       n -- second dimension of a
--c
--c       output:
--c       krank -- numerical rank of the ID
--c       list -- indices of the columns in the ID
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns in a;
--c               proj doubles as a work array in the present routine, so
--c               must be at least m*n complex*16 elements long
--c
--c       work:
--c       rnorms -- must be at least n real*8 elements long
--c
--c       _N.B._: proj must be at least m*n complex*16 elements long
--c
--        implicit none
--        integer m,n,krank,list(n),j,k
--        real*8 eps,rnorms(n)
--        complex*16 a(m,n),proj(m,n)
--c
--c
--c       Copy a into proj.
--c
--        do k = 1,n
--          do j = 1,m
--            proj(j,k) = a(j,k)
--          enddo ! j
--        enddo ! k
--c
--c
--c       ID proj.
--c
--        call idzp_id(eps,m,n,proj,krank,list,rnorms)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzp_aid1(eps,n2,n,kranki,proj,krank,list,rnorms)
--c
--c       IDs the uppermost kranki x n block of the n2 x n matrix
--c       input as proj.
--c
--c       input:
--c       eps -- precision of the decomposition to be constructed
--c       n2 -- first dimension of proj as input
--c       n -- second dimension of proj as input
--c       kranki -- number of rows to extract from proj
--c       proj -- matrix containing the kranki x n block to be ID'd
--c
--c       output:
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns
--c               in the original matrix being ID'd
--c       krank -- numerical rank of the ID
--c       list -- indices of the columns in the ID
--c
--c       work:
--c       rnorms -- must be at least n real*8 elements long
--c
--        implicit none
--        integer n,n2,kranki,krank,list(n),j,k
--        real*8 eps,rnorms(n)
--        complex*16 proj(n2*n)
--c
--c
--c       Move the uppermost kranki x n block of the n2 x n matrix proj
--c       to the beginning of proj.
--c
--        do k = 1,n
--          do j = 1,kranki
--            proj(j+kranki*(k-1)) = proj(j+n2*(k-1))
--          enddo ! j
--        enddo ! k
--c
--c
--c       ID proj.
--c
--        call idzp_id(eps,kranki,n,proj,krank,list,rnorms)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_estrank(eps,m,n,a,w,krank,ra)
--c
--c       estimates the numerical rank krank of an m x n matrix a
--c       to precision eps. This routine applies n2 random vectors
--c       to a, obtaining ra, where n2 is the greatest integer
--c       less than or equal to m such that n2 is a positive integer
--c       power of two. krank is typically about 8 higher than
--c       the actual numerical rank.
--c
--c       input:
--c       eps -- precision defining the numerical rank
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       a -- matrix whose rank is to be estimated
--c       w -- initialization array that has been constructed
--c            by routine idz_frmi
--c
--c       output:
--c       krank -- estimate of the numerical rank of a;
--c                this routine returns krank = 0 when the actual
--c                numerical rank is nearly full (that is,
--c                greater than n - 8 or n2 - 8)
--c       ra -- product of an n2 x m random matrix and the m x n matrix
--c             a, where n2 is the greatest integer less than or equal
--c             to m such that n2 is a positive integer power of two;
--c             ra doubles as a work array in the present routine, and so
--c             must be at least n*n2+(n+1)*(n2+1) complex*16 elements
--c             long
--c
--c       _N.B._: ra must be at least n*n2+(n2+1)*(n+1) complex*16
--c               elements long for use in the present routine
--c               (here, n2 is the greatest integer less than or equal
--c               to m, such that n2 is a positive integer power of two).
--c               This routine returns krank = 0 when the actual
--c               numerical rank is nearly full.
--c
--        implicit none
--        integer m,n,krank,n2,irat,lrat,iscal,lscal,ira,lra,lra2
--        real*8 eps
--        complex*16 a(m,n),ra(*),w(17*m+70)
--c
--c
--c       Extract from the array w initialized by routine idz_frmi
--c       the greatest integer less than or equal to m that is
--c       a positive integer power of two.
--c
--        n2 = w(2)
--c
--c
--c       Allocate memory in ra.
--c
--        lra = 0
--c
--        ira = lra+1
--        lra2 = n2*n
--        lra = lra+lra2
--c
--        irat = lra+1
--        lrat = n*(n2+1)
--        lra = lra+lrat
--c
--        iscal = lra+1
--        lscal = n2+1
--        lra = lra+lscal
--c
--        call idz_estrank0(eps,m,n,a,w,n2,krank,ra(ira),ra(irat),
--     1                    ra(iscal))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_estrank0(eps,m,n,a,w,n2,krank,ra,rat,scal)
--c
--c       routine idz_estrank serves as a memory wrapper
--c       for the present routine. (Please see routine idz_estrank
--c       for further documentation.)
--c
--        implicit none
--        integer m,n,n2,krank,ifrescal,k,nulls,j
--        real*8 eps,scal(n2+1),ss,ssmax
--        complex*16 a(m,n),ra(n2,n),residual,w(17*m+70),rat(n,n2+1)
--c
--c
--c       Apply the random matrix to every column of a, obtaining ra.
--c
--        do k = 1,n
--          call idz_frm(m,n2,w,a(1,k),ra(1,k))
--        enddo ! k
--c
--c
--c       Compute the sum of squares of the entries in each column of ra
--c       and the maximum of all such sums.
--c
--        ssmax = 0
--c
--        do k = 1,n
--c
--          ss = 0
--          do j = 1,m
--            ss = ss+a(j,k)*conjg(a(j,k))
--          enddo ! j
--c
--          if(ss .gt. ssmax) ssmax = ss
--c
--        enddo ! k
--c
--c
--c       Transpose ra to obtain rat.
--c
--        call idz_transposer(n2,n,ra,rat)
--c
--c
--        krank = 0
--        nulls = 0
--c
--c
--c       Loop until nulls = 7, krank+nulls = n2, or krank+nulls = n.
--c
-- 1000   continue
--c
--c
--          if(krank .gt. 0) then
--c
--c           Apply the previous Householder transformations
--c           to rat(:,krank+1).
--c
--            ifrescal = 0
--c
--            do k = 1,krank
--              call idz_houseapp(n-k+1,rat(1,k),rat(k,krank+1),
--     1                          ifrescal,scal(k),rat(k,krank+1))
--            enddo ! k
--c
--          endif ! krank .gt. 0
--c
--c
--c         Compute the Householder vector associated
--c         with rat(krank+1:*,krank+1).
--c
--          call idz_house(n-krank,rat(krank+1,krank+1),
--     1                   residual,rat(1,krank+1),scal(krank+1))
--c
--c
--          krank = krank+1
--          if(abs(residual) .le. eps*sqrt(ssmax)) nulls = nulls+1
--c
--c
--        if(nulls .lt. 7 .and. krank+nulls .lt. n2
--     1   .and. krank+nulls .lt. n)
--     2   goto 1000
--c
--c
--        if(nulls .lt. 7) krank = 0
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_transposer(m,n,a,at)
--c
--c       transposes a to obtain at.
--c
--c       input:
--c       m -- first dimension of a, and second dimension of at
--c       n -- second dimension of a, and first dimension of at
--c       a -- matrix to be transposed
--c
--c       output:
--c       at -- transpose of a
--c
--        implicit none
--        integer m,n,j,k
--        complex*16 a(m,n),at(n,m)
--c
--c
--        do k = 1,n
--          do j = 1,m
--c
--            at(k,j) = a(j,k)
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idzp_asvd.f b/scipy/linalg/src/id_dist/src/idzp_asvd.f
-deleted file mode 100644
-index 4704f5bbd..000000000
---- a/scipy/linalg/src/id_dist/src/idzp_asvd.f
-+++ /dev/null
-@@ -1,207 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzp_asvd computes the SVD, to a specified precision,
--c       of an arbitrary matrix. This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idzp_asvd(lw,eps,m,n,a,winit,krank,iu,iv,is,w,ier)
--c
--c       constructs a rank-krank SVD  U Sigma V^*  approximating a
--c       to precision eps, where U is an m x krank matrix whose
--c       columns are orthonormal, V is an n x krank matrix whose
--c       columns are orthonormal, and Sigma is a diagonal krank x krank
--c       matrix whose entries are all nonnegative.
--c       The entries of U are stored in w, starting at w(iu);
--c       the entries of V are stored in w, starting at w(iv).
--c       The diagonal entries of Sigma are stored in w,
--c       starting at w(is). This routine uses a randomized algorithm.
--c
--c       input:
--c       lw -- maximum usable length (in complex*16 elements)
--c             of the array w
--c       eps -- precision of the desired approximation
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       a -- matrix to be approximated; the present routine does not
--c            alter a
--c       winit -- initialization array that has been constructed
--c                by routine idz_frmi
--c
--c       output:
--c       krank -- rank of the SVD constructed
--c       iu -- index in w of the first entry of the matrix
--c             of orthonormal left singular vectors of a
--c       iv -- index in w of the first entry of the matrix
--c             of orthonormal right singular vectors of a
--c       is -- index in w of the first entry of the array
--c             of singular values of a
--c       w -- array containing the singular values and singular vectors
--c            of a; w doubles as a work array, and so must be at least
--c            max( (krank+1)*(3*m+5*n+11)+8*krank**2, (2*n+1)*(n2+1) )
--c            complex*16 elements long, where n2 is the greatest integer
--c            less than or equal to m, such that n2 is
--c            a positive integer power of two; krank is the rank output
--c            by this routine
--c       ier -- 0 when the routine terminates successfully;
--c              -1000 when lw is too small;
--c              other nonzero values when idz_id2svd bombs
--c
--c       _N.B._: w must be at least
--c               max( (krank+1)*(3*m+5*n+11)+8*krank^2, (2*n+1)*(n2+1) )
--c               complex*16 elements long, where n2 is
--c               the greatest integer less than or equal to m,
--c               such that n2 is a positive integer power of two;
--c               krank is the rank output by this routine.
--c               Also, the algorithm used by this routine is randomized.
--c
--        implicit none
--        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
--     1          iwork,lwork,k,ier,lw2,iu,iv,is,iui,ivi,isi,lu,lv,ls
--        real*8 eps
--        complex*16 a(m,n),winit(17*m+70),w(*)
--c
--c
--c       Allocate memory in w.
--c
--        lw2 = 0
--c
--        ilist = lw2+1
--        llist = n
--        lw2 = lw2+llist
--c
--        iproj = lw2+1
--c
--c
--c       ID a.
--c
--        call idzp_aid(eps,m,n,a,winit,krank,w(ilist),w(iproj))
--c
--c
--        if(krank .gt. 0) then
--c
--c
--c         Allocate more memory in w.
--c
--          lproj = krank*(n-krank)
--          lw2 = lw2+lproj
--c
--          icol = lw2+1
--          lcol = m*krank
--          lw2 = lw2+lcol
--c
--          iui = lw2+1
--          lu = m*krank
--          lw2 = lw2+lu
--c
--          ivi = lw2+1
--          lv = n*krank
--          lw2 = lw2+lv
--c
--          isi = lw2+1
--          ls = krank
--          lw2 = lw2+ls
--c
--          iwork = lw2+1
--          lwork = (krank+1)*(m+3*n+10)+9*krank**2
--          lw2 = lw2+lwork
--c
--c
--          if(lw .lt. lw2) then
--            ier = -1000
--            return
--          endif
--c
--c
--          call idzp_asvd0(m,n,a,krank,w(ilist),w(iproj),
--     1                    w(iui),w(ivi),w(isi),ier,w(icol),w(iwork))
--          if(ier .ne. 0) return
--c
--c
--          iu = 1
--          iv = iu+lu
--          is = iv+lv
--c
--c
--c         Copy the singular values and singular vectors
--c         into their proper locations.
--c
--          do k = 1,lu
--            w(iu+k-1) = w(iui+k-1)
--          enddo ! k
--c
--          do k = 1,lv
--            w(iv+k-1) = w(ivi+k-1)
--          enddo ! k
--c
--          call idz_realcomplex(ls,w(isi),w(is))
--c
--c
--        endif ! krank .gt. 0
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzp_asvd0(m,n,a,krank,list,proj,u,v,s,ier,
--     1                        col,work)
--c
--c       routine idzp_asvd serves as a memory wrapper
--c       for the present routine (please see routine idzp_asvd
--c       for further documentation).
--c
--        implicit none
--        integer m,n,krank,list(n),ier
--        real*8 s(krank)
--        complex*16 a(m,n),u(m,krank),v(n,krank),
--     1             proj(krank,n-krank),col(m,krank),
--     2             work((krank+1)*(m+3*n+10)+9*krank**2)
--c
--c
--c       Collect together the columns of a indexed by list into col.
--c
--        call idz_copycols(m,n,a,krank,list,col)
--c
--c
--c       Convert the ID to an SVD.
--c
--        call idz_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_realcomplex(n,a,b)
--c
--c       copies the real*8 array a into the complex*16 array b.
--c
--c       input:
--c       n -- length of a and b
--c       a -- real*8 array to be copied into b
--c
--c       output:
--c       b -- complex*16 copy of a
--c
--        integer n,k
--        real*8 a(n)
--        complex*16 b(n)
--c
--c
--        do k = 1,n
--          b(k) = a(k)
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idzp_rid.f b/scipy/linalg/src/id_dist/src/idzp_rid.f
-deleted file mode 100644
-index f12623aed..000000000
---- a/scipy/linalg/src/id_dist/src/idzp_rid.f
-+++ /dev/null
-@@ -1,379 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzp_rid computes the ID, to a specified precision,
--c       of a matrix specified by a routine for applying its adjoint
--c       to arbitrary vectors. This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idzp_rid(lproj,eps,m,n,matveca,p1,p2,p3,p4,
--     1                      krank,list,proj,ier)
--c
--c       computes the ID of a, i.e., lists in list the indices
--c       of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                        krank
--c       a(j,list(k))  =  Sigma  a(j,list(l)) * proj(l,k-krank)       (*)
--c                         l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon dimensioned epsilon(m,n-krank)
--c       such that the greatest singular value of epsilon
--c       <= the greatest singular value of a * eps.
--c
--c       input:
--c       lproj -- maximum usable length (in complex*16 elements)
--c                of the array proj
--c       eps -- precision to which the ID is to be computed
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       matveca -- routine which applies the adjoint
--c                  of the matrix to be ID'd to an arbitrary vector;
--c                  this routine must have a calling sequence
--c                  of the form
--c
--c                  matveca(m,x,n,y,p1,p2,p3,p4),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the adjoint
--c                  of the matrix is to be applied,
--c                  n is the length of y,
--c                  y is the product of the adjoint of the matrix and x,
--c                  and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matveca
--c       p2 -- parameter to be passed to routine matveca
--c       p3 -- parameter to be passed to routine matveca
--c       p4 -- parameter to be passed to routine matveca
--c
--c       output:
--c       krank -- numerical rank
--c       list -- indices of the columns in the ID
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns
--c               in the original matrix being ID'd;
--c               the present routine uses proj as a work array, too, so
--c               proj must be at least m+1 + 2*n*(krank+1) complex*16
--c               elements long, where krank is the rank output
--c               by the present routine
--c       ier -- 0 when the routine terminates successfully;
--c              -1000 when lproj is too small
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c               proj must be at least m+1 + 2*n*(krank+1) complex*16
--c               elements long, where krank is the rank output
--c               by the present routine.
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,n,list(n),krank,lw,iwork,lwork,ira,kranki,lproj,
--     1          lra,ier,k
--        real*8 eps
--        complex*16 p1,p2,p3,p4,proj(*)
--        external matveca
--c
--c
--        ier = 0
--c
--c
--c       Allocate memory in proj.
--c
--        lw = 0
--c
--        iwork = lw+1
--        lwork = m+2*n+1
--        lw = lw+lwork
--c
--        ira = lw+1
--c
--c
--c       Find the rank of a.
--c
--        lra = lproj-lwork
--        call idz_findrank(lra,eps,m,n,matveca,p1,p2,p3,p4,
--     1                    kranki,proj(ira),ier,proj(iwork))
--        if(ier .ne. 0) return
--c
--c
--        if(lproj .lt. lwork+2*kranki*n) then
--          ier = -1000
--          return
--        endif
--c
--c
--c       Take the adjoint of ra.
--c
--        call idz_adjointer(n,kranki,proj(ira),proj(ira+kranki*n))
--c
--c
--c       Move the adjoint thus obtained to the beginning of proj.
--c
--        do k = 1,kranki*n
--          proj(k) = proj(ira+kranki*n+k-1)
--        enddo ! k
--c
--c
--c       ID the adjoint.
--c
--        call idzp_id(eps,kranki,n,proj,krank,list,proj(1+kranki*n))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_findrank(lra,eps,m,n,matveca,p1,p2,p3,p4,
--     1                          krank,ra,ier,w)
--c
--c       estimates the numerical rank krank of a matrix a to precision
--c       eps, where the routine matveca applies the adjoint of a
--c       to an arbitrary vector. This routine applies the adjoint of a
--c       to krank random vectors, and returns the resulting vectors
--c       as the columns of ra.
--c
--c       input:
--c       lra -- maximum usable length (in complex*16 elements)
--c              of array ra
--c       eps -- precision defining the numerical rank
--c       m -- first dimension of a
--c       n -- second dimension of a
--c       matveca -- routine which applies the adjoint
--c                  of the matrix whose rank is to be estimated
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matveca(m,x,n,y,p1,p2,p3,p4),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the adjoint
--c                  of the matrix is to be applied,
--c                  n is the length of y,
--c                  y is the product of the adjoint of the matrix and x,
--c                  and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matveca
--c       p2 -- parameter to be passed to routine matveca
--c       p3 -- parameter to be passed to routine matveca
--c       p4 -- parameter to be passed to routine matveca
--c
--c       output:
--c       krank -- estimate of the numerical rank of a
--c       ra -- product of the adjoint of a and a matrix whose entries
--c             are pseudorandom realizations of i.i.d. random numbers,
--c             uniformly distributed on [0,1];
--c             ra must be at least 2*n*krank complex*16 elements long
--c       ier -- 0 when the routine terminates successfully;
--c              -1000 when lra is too small
--c
--c       work:
--c       w -- must be at least m+2*n+1 complex*16 elements long
--c
--c       _N.B._: ra must be at least 2*n*krank complex*16 elements long.
--c               Also, the algorithm used by this routine is randomized.
--c
--        implicit none
--        integer m,n,lw,krank,ix,lx,iy,ly,iscal,lscal,lra,ier
--        real*8 eps
--        complex*16 p1,p2,p3,p4,ra(n,*),w(m+2*n+1)
--        external matveca
--c
--c
--        lw = 0
--c
--        ix = lw+1
--        lx = m
--        lw = lw+lx
--c
--        iy = lw+1
--        ly = n
--        lw = lw+ly
--c
--        iscal = lw+1
--        lscal = n+1
--        lw = lw+lscal
--c
--c
--        call idz_findrank0(lra,eps,m,n,matveca,p1,p2,p3,p4,
--     1                     krank,ra,ier,w(ix),w(iy),w(iscal))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_findrank0(lra,eps,m,n,matveca,p1,p2,p3,p4,
--     1                           krank,ra,ier,x,y,scal)
--c
--c       routine idz_findrank serves as a memory wrapper
--c       for the present routine. (Please see routine idz_findrank
--c       for further documentation.)
--c
--        implicit none
--        integer m,n,krank,ifrescal,k,lra,ier,m2
--        real*8 eps,enorm
--        complex*16 x(m),ra(n,2,*),p1,p2,p3,p4,scal(n+1),y(n),residual
--        external matveca
--c
--c
--        ier = 0
--c
--c
--        krank = 0
--c
--c
--c       Loop until the relative residual is greater than eps,
--c       or krank = m or krank = n.
--c
-- 1000   continue
--c
--c
--          if(lra .lt. n*2*(krank+1)) then
--            ier = -1000
--            return
--          endif
--c
--c
--c         Apply the adjoint of a to a random vector.
--c
--          m2 = m*2
--          call id_srand(m2,x)
--          call matveca(m,x,n,ra(1,1,krank+1),p1,p2,p3,p4)
--c
--          do k = 1,n
--            y(k) = ra(k,1,krank+1)
--          enddo ! k
--c
--c
--          if(krank .eq. 0) then
--c
--c           Compute the Euclidean norm of y.
--c
--            enorm = 0
--c
--            do k = 1,n
--              enorm = enorm + y(k)*conjg(y(k))
--            enddo ! k
--c
--            enorm = sqrt(enorm)
--c
--          endif ! krank .eq. 0
--c
--c
--          if(krank .gt. 0) then
--c
--c           Apply the previous Householder transformations to y.
--c
--            ifrescal = 0
--c
--            do k = 1,krank
--              call idz_houseapp(n-k+1,ra(1,2,k),y(k),
--     1                          ifrescal,scal(k),y(k))
--            enddo ! k
--c
--          endif ! krank .gt. 0
--c
--c
--c         Compute the Householder vector associated with y.
--c
--          call idz_house(n-krank,y(krank+1),
--     1                   residual,ra(1,2,krank+1),scal(krank+1))
--c
--c
--          krank = krank+1
--c
--c
--        if(abs(residual) .gt. eps*enorm
--     1   .and. krank .lt. m .and. krank .lt. n)
--     2   goto 1000
--c
--c
--c       Delete the Householder vectors from the array ra.
--c
--        call idz_crunch(n,krank,ra)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_crunch(n,l,a)
--c
--c       removes every other block of n entries from a vector.
--c
--c       input:
--c       n -- length of each block to remove
--c       l -- half of the total number of blocks
--c       a -- original array
--c
--c       output:
--c       a -- array with every other block of n entries removed
--c
--        implicit none
--        integer j,k,n,l
--        complex*16 a(n,2*l)
--c
--c
--        do j = 2,l
--          do k = 1,n
--c
--            a(k,j) = a(k,2*j-1)
--c
--          enddo ! k
--        enddo ! j
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_adjointer(m,n,a,aa)
--c
--c       forms the adjoint aa of a.
--c
--c       input:
--c       m -- first dimension of a, and second dimension of aa
--c       n -- second dimension of a, and first dimension of aa
--c       a -- matrix whose adjoint is to be taken
--c
--c       output:
--c       aa -- adjoint of a
--c
--        implicit none
--        integer m,n,j,k
--        complex*16 a(m,n),aa(n,m)
--c
--c
--        do k = 1,n
--          do j = 1,m
--c
--            aa(k,j) = conjg(a(j,k))
--c
--          enddo ! j
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idzp_rsvd.f b/scipy/linalg/src/id_dist/src/idzp_rsvd.f
-deleted file mode 100644
-index e34b3e374..000000000
---- a/scipy/linalg/src/id_dist/src/idzp_rsvd.f
-+++ /dev/null
-@@ -1,244 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzp_rsvd computes the SVD, to a specified precision,
--c       of a matrix specified by routines for applying the matrix
--c       and its adjoint to arbitrary vectors.
--c       This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idzp_rsvd(lw,eps,m,n,matveca,p1t,p2t,p3t,p4t,
--     1                       matvec,p1,p2,p3,p4,krank,iu,iv,is,w,ier)
--c
--c       constructs a rank-krank SVD  U Sigma V^*  approximating a
--c       to precision eps, where matveca is a routine which applies a^*
--c       to an arbitrary vector, and matvec is a routine
--c       which applies a to an arbitrary vector; U is an m x krank
--c       matrix whose columns are orthonormal, V is an n x krank
--c       matrix whose columns are orthonormal, and Sigma is a diagonal
--c       krank x krank matrix whose entries are all nonnegative.
--c       The entries of U are stored in w, starting at w(iu);
--c       the entries of V are stored in w, starting at w(iv).
--c       The diagonal entries of Sigma are stored in w,
--c       starting at w(is). This routine uses a randomized algorithm.
--c
--c       input:
--c       lw -- maximum usable length (in complex*16 elements)
--c             of the array w
--c       eps -- precision of the desired approximation
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       matveca -- routine which applies the adjoint
--c                  of the matrix to be SVD'd
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matveca(m,x,n,y,p1t,p2t,p3t,p4t),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the adjoint
--c                  of the matrix is to be applied,
--c                  n is the length of y,
--c                  y is the product of the adjoint of the matrix and x,
--c                  and p1t, p2t, p3t, and p4t are user-specified
--c                  parameters
--c       p1t -- parameter to be passed to routine matveca
--c       p2t -- parameter to be passed to routine matveca
--c       p3t -- parameter to be passed to routine matveca
--c       p4t -- parameter to be passed to routine matveca
--c       matvec -- routine which applies the matrix to be SVD'd
--c                 to an arbitrary vector; this routine must have
--c                 a calling sequence of the form
--c
--c                 matvec(n,x,m,y,p1,p2,p3,p4),
--c
--c                 where n is the length of x,
--c                 x is the vector to which the matrix is to be applied,
--c                 m is the length of y,
--c                 y is the product of the matrix and x,
--c                 and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvec
--c       p2 -- parameter to be passed to routine matvec
--c       p3 -- parameter to be passed to routine matvec
--c       p4 -- parameter to be passed to routine matvec
--c
--c       output:
--c       krank -- rank of the SVD constructed
--c       iu -- index in w of the first entry of the matrix
--c             of orthonormal left singular vectors of a
--c       iv -- index in w of the first entry of the matrix
--c             of orthonormal right singular vectors of a
--c       is -- index in w of the first entry of the array
--c             of singular values of a; the singular values are stored
--c             as complex*16 numbers whose imaginary parts are zeros
--c       w -- array containing the singular values and singular vectors
--c            of a; w doubles as a work array, and so must be at least
--c            (krank+1)*(3*m+5*n+11)+8*krank^2 complex*16 elements long,
--c            where krank is the rank returned by the present routine
--c       ier -- 0 when the routine terminates successfully;
--c              -1000 when lw is too small;
--c              other nonzero values when idz_id2svd bombs
--c
--c       _N.B._: w must be at least (krank+1)*(3*m+5*n+11)+8*krank**2
--c               complex*16 elements long, where krank is the rank
--c               returned by the present routine. Also, the algorithm
--c               used by the present routine is randomized.
--c
--        implicit none
--        integer m,n,krank,lw,lw2,ilist,llist,iproj,icol,lcol,lp,
--     1          iwork,lwork,ier,lproj,iu,iv,is,lu,lv,ls,iui,ivi,isi,k
--        real*8 eps
--        complex*16 p1t,p2t,p3t,p4t,p1,p2,p3,p4,w(*)
--        external matveca,matvec
--c
--c
--c       Allocate some memory.
--c
--        lw2 = 0
--c
--        ilist = lw2+1
--        llist = n
--        lw2 = lw2+llist
--c
--        iproj = lw2+1
--c
--c
--c       ID a.
--c
--        lp = lw-lw2
--        call idzp_rid(lp,eps,m,n,matveca,p1t,p2t,p3t,p4t,krank,
--     1                w(ilist),w(iproj),ier)
--        if(ier .ne. 0) return
--c
--c
--        if(krank .gt. 0) then
--c
--c
--c         Allocate more memory.
--c
--          lproj = krank*(n-krank)
--          lw2 = lw2+lproj
--c
--          icol = lw2+1
--          lcol = m*krank
--          lw2 = lw2+lcol
--c
--          iui = lw2+1
--          lu = m*krank
--          lw2 = lw2+lu
--c
--          ivi = lw2+1
--          lv = n*krank
--          lw2 = lw2+lv
--c
--          isi = lw2+1
--          ls = krank
--          lw2 = lw2+ls
--c
--          iwork = lw2+1
--          lwork = (krank+1)*(m+3*n+10)+9*krank**2
--          lw2 = lw2+lwork
--c
--c
--          if(lw .lt. lw2) then
--            ier = -1000
--            return
--          endif
--c
--c
--          call idzp_rsvd0(m,n,matveca,p1t,p2t,p3t,p4t,
--     1                    matvec,p1,p2,p3,p4,krank,w(iui),w(ivi),
--     2                    w(isi),ier,w(ilist),w(iproj),w(icol),
--     3                    w(iwork))
--          if(ier .ne. 0) return
--c
--c
--          iu = 1
--          iv = iu+lu
--          is = iv+lv
--c
--c
--c         Copy the singular values and singular vectors
--c         into their proper locations.
--c
--          do k = 1,lu
--            w(iu+k-1) = w(iui+k-1)
--          enddo ! k
--c
--          do k = 1,lv
--            w(iv+k-1) = w(ivi+k-1)
--          enddo ! k
--c
--          call idz_reco(ls,w(isi),w(is))
--c
--c
--        endif ! krank .gt. 0
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzp_rsvd0(m,n,matveca,p1t,p2t,p3t,p4t,
--     1                        matvec,p1,p2,p3,p4,krank,u,v,s,ier,
--     2                        list,proj,col,work)
--c
--c       routine idzp_rsvd serves as a memory wrapper
--c       for the present routine (please see routine idzp_rsvd
--c       for further documentation).
--c
--        implicit none
--        integer m,n,krank,list(n),ier
--        real*8 s(krank)
--        complex*16 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
--     1             proj(krank,n-krank),col(m*krank),
--     2             work((krank+1)*(m+3*n+10)+9*krank**2)
--        external matveca,matvec
--c
--c
--c       Collect together the columns of a indexed by list into col.
--c
--        call idz_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,col,work)
--c
--c
--c       Convert the ID to an SVD.
--c
--        call idz_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idz_reco(n,a,b)
--c
--c       copies the real*8 array a into the complex*16 array b.
--c
--c       input:
--c       n -- length of a and b
--c       a -- real*8 array to be copied into b
--c
--c       output:
--c       b -- complex*16 copy of a
--c
--        integer n,k
--        real*8 a(n)
--        complex*16 b(n)
--c
--c
--        do k = 1,n
--          b(k) = a(k)
--        enddo ! k
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idzr_aid.f b/scipy/linalg/src/id_dist/src/idzr_aid.f
-deleted file mode 100644
-index e8380ecd3..000000000
---- a/scipy/linalg/src/id_dist/src/idzr_aid.f
-+++ /dev/null
-@@ -1,209 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzr_aid computes the ID, to a specified rank,
--c       of an arbitrary matrix. This routine is randomized.
--c
--c       routine idzr_aidi initializes routine idzr_aid.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idzr_aid(m,n,a,krank,w,list,proj)
--c
--c       computes the ID of the matrix a, i.e., lists in list
--c       the indices of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                       min(m,n,krank)
--c       a(j,list(k))  =     Sigma      a(j,list(l)) * proj(l,k-krank)(*)
--c                            l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
--c       whose norm is (hopefully) minimized by the pivoting procedure.
--c
--c       input:
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       a -- matrix to be ID'd; the present routine does not alter a
--c       krank -- rank of the ID to be constructed
--c       w -- initialization array that routine idzr_aidi
--c            has constructed
--c
--c       output:
--c       list -- indices of the columns in the ID
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns
--c               in the original matrix being ID'd
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,n,krank,list(n),lw,ir,lr,lw2,iw
--        complex*16 a(m,n),proj(krank*(n-krank)),
--     1             w((2*krank+17)*n+21*m+80)
--c
--c
--c       Allocate memory in w.
--c
--        lw = 0
--c
--        iw = lw+1
--        lw2 = 21*m+80+n
--        lw = lw+lw2
--c
--        ir = lw+1
--        lr = (krank+8)*2*n
--        lw = lw+lr
--c
--c
--        call idzr_aid0(m,n,a,krank,w(iw),list,proj,w(ir))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzr_aid0(m,n,a,krank,w,list,proj,r)
--c
--c       routine idzr_aid serves as a memory wrapper
--c       for the present routine
--c       (see idzr_aid for further documentation).
--c
--        implicit none
--        integer k,l,m,n2,n,krank,list(n),mn,lproj
--        complex*16 a(m,n),r(krank+8,2*n),proj(krank,n-krank),
--     1             w(21*m+80+n)
--c
--c       Please note that the second dimension of r is 2*n
--c       (instead of n) so that if krank+8 >= m/2, then
--c       we can copy the whole of a into r.
--c
--c
--c       Retrieve the number of random test vectors
--c       and the greatest integer less than m that is
--c       a positive integer power of two.
--c
--        l = w(1)
--        n2 = w(2)
--c
--c
--        if(l .lt. n2 .and. l .le. m) then
--c
--c         Apply the random matrix.
--c
--          do k = 1,n
--            call idz_sfrm(l,m,n2,w(11),a(1,k),r(1,k))
--          enddo ! k
--c
--c         ID r.
--c
--          call idzr_id(l,n,r,krank,list,w(20*m+81))
--c
--c         Retrieve proj from r.
--c
--          lproj = krank*(n-krank)
--          call idzr_copyzarr(lproj,r,proj)
--c
--        endif
--c
--c
--        if(l .ge. n2 .or. l .gt. m) then
--c
--c         ID a directly.
--c
--          mn = m*n
--          call idzr_copyzarr(mn,a,r)
--          call idzr_id(m,n,r,krank,list,w(20*m+81))
--c
--c         Retrieve proj from r.
--c
--          lproj = krank*(n-krank)
--          call idzr_copyzarr(lproj,r,proj)
--c
--        endif
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzr_copyzarr(n,a,b)
--c
--c       copies a into b.
--c
--c       input:
--c       n -- length of a and b
--c       a -- array to copy into b
--c
--c       output:
--c       b -- copy of a
--c
--        implicit none
--        integer n,k
--        complex*16 a(n),b(n)
--c
--c
--        do k = 1,n
--          b(k) = a(k)
--        enddo ! k
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzr_aidi(m,n,krank,w)
--c
--c       initializes the array w for using routine idzr_aid.
--c
--c       input:
--c       m -- number of rows in the matrix to be ID'd
--c       n -- number of columns in the matrix to be ID'd
--c       krank -- rank of the ID to be constructed
--c
--c       output:
--c       w -- initialization array for using routine idzr_aid
--c
--        implicit none
--        integer m,n,krank,l,n2
--        complex*16 w((2*krank+17)*n+21*m+80)
--c
--c
--c       Set the number of random test vectors to 8 more than the rank.
--c
--        l = krank+8
--        w(1) = l
--c
--c
--c       Initialize the rest of the array w.
--c
--        n2 = 0
--        if(l .le. m) call idz_sfrmi(l,m,n2,w(11))
--        w(2) = n2
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idzr_asvd.f b/scipy/linalg/src/id_dist/src/idzr_asvd.f
-deleted file mode 100644
-index 55ad61203..000000000
---- a/scipy/linalg/src/id_dist/src/idzr_asvd.f
-+++ /dev/null
-@@ -1,118 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzr_aid computes the SVD, to a specified rank,
--c       of an arbitrary matrix. This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idzr_asvd(m,n,a,krank,w,u,v,s,ier)
--c
--c       constructs a rank-krank SVD  u diag(s) v^*  approximating a,
--c       where u is an m x krank matrix whose columns are orthonormal,
--c       v is an n x krank matrix whose columns are orthonormal,
--c       and diag(s) is a diagonal krank x krank matrix whose entries
--c       are all nonnegative. This routine uses a randomized algorithm.
--c
--c       input:
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       a -- matrix to be decomposed; the present routine does not
--c            alter a
--c       krank -- rank of the SVD being constructed
--c       w -- initialization array that routine idzr_aidi
--c            has constructed (for use in the present routine,
--c            w must be at least
--c            (2*krank+22)*m+(6*krank+21)*n+8*krank**2+10*krank+90
--c            complex*16 elements long)
--c
--c       output:
--c       u -- matrix of orthonormal left singular vectors of a
--c       v -- matrix of orthonormal right singular vectors of a
--c       s -- array of singular values of a
--c       ier -- 0 when the routine terminates successfully;
--c              nonzero otherwise
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c
--        implicit none
--        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
--     1          iwork,lwork,iwinit,lwinit,ier
--        real*8 s(krank)
--        complex*16 a(m,n),u(m,krank),v(n,krank),
--     1             w((2*krank+22)*m+(6*krank+21)*n+8*krank**2
--     2              +10*krank+90)
--c
--c
--c       Allocate memory in w.
--c
--        lw = 0
--c
--        iwinit = lw+1
--        lwinit = (2*krank+17)*n+21*m+80
--        lw = lw+lwinit
--c
--        ilist = lw+1
--        llist = n
--        lw = lw+llist
--c
--        iproj = lw+1
--        lproj = krank*(n-krank)
--        lw = lw+lproj
--c
--        icol = lw+1
--        lcol = m*krank
--        lw = lw+lcol
--c
--        iwork = lw+1
--        lwork = (krank+1)*(m+3*n+10)+9*krank**2
--        lw = lw+lwork
--c
--c
--        call idzr_asvd0(m,n,a,krank,w(iwinit),u,v,s,ier,
--     1                  w(ilist),w(iproj),w(icol),w(iwork))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzr_asvd0(m,n,a,krank,winit,u,v,s,ier,
--     1                        list,proj,col,work)
--c
--c       routine idzr_asvd serves as a memory wrapper
--c       for the present routine (please see routine idzr_asvd
--c       for further documentation).
--c
--        implicit none
--        integer m,n,krank,list(n),ier
--        real*8 s(krank)
--        complex*16 a(m,n),u(m,krank),v(n,krank),
--     1             proj(krank,n-krank),col(m*krank),
--     2             winit((2*krank+17)*n+21*m+80),
--     3             work((krank+1)*(m+3*n+10)+9*krank**2)
--c
--c
--c       ID a.
--c
--        call idzr_aid(m,n,a,krank,winit,list,proj)
--c
--c
--c       Collect together the columns of a indexed by list into col.
--c
--        call idz_copycols(m,n,a,krank,list,col)
--c
--c
--c       Convert the ID to an SVD.
--c
--        call idz_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idzr_rid.f b/scipy/linalg/src/id_dist/src/idzr_rid.f
-deleted file mode 100644
-index cf8fcaacf..000000000
---- a/scipy/linalg/src/id_dist/src/idzr_rid.f
-+++ /dev/null
-@@ -1,156 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzr_rid computes the ID, to a specified rank,
--c       of a matrix specified by a routine for applying its adjoint
--c       to arbitrary vectors. This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idzr_rid(m,n,matveca,p1,p2,p3,p4,krank,list,proj)
--c
--c       computes the ID of a matrix "a" specified by
--c       the routine matveca -- matveca must apply the adjoint
--c       of the matrix being ID'd to an arbitrary vector --
--c       i.e., the present routine lists in list the indices
--c       of krank columns of a such that
--c
--c       a(j,list(k))  =  a(j,list(k))
--c
--c       for all j = 1, ..., m; k = 1, ..., krank, and
--c
--c                       min(m,n,krank)
--c       a(j,list(k))  =     Sigma      a(j,list(l)) * proj(l,k-krank)(*)
--c                            l=1
--c
--c                     +  epsilon(j,k-krank)
--c
--c       for all j = 1, ..., m; k = krank+1, ..., n,
--c
--c       for some matrix epsilon, dimensioned epsilon(m,n-krank),
--c       whose norm is (hopefully) minimized by the pivoting procedure.
--c
--c       input:
--c       m -- number of rows in the matrix to be ID'd
--c       n -- number of columns in the matrix to be ID'd
--c       matveca -- routine which applies the adjoint
--c                  of the matrix to be ID'd to an arbitrary vector;
--c                  this routine must have a calling sequence
--c                  of the form
--c
--c                  matveca(m,x,n,y,p1,p2,p3,p4),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the adjoint
--c                  of the matrix is to be applied,
--c                  n is the length of y,
--c                  y is the product of the adjoint of the matrix and x,
--c                  and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matveca
--c       p2 -- parameter to be passed to routine matveca
--c       p3 -- parameter to be passed to routine matveca
--c       p4 -- parameter to be passed to routine matveca
--c       krank -- rank of the ID to be constructed
--c
--c       output:
--c       list -- indices of the columns in the ID
--c       proj -- matrix of coefficients needed to interpolate
--c               from the selected columns to the other columns
--c               in the original matrix being ID'd;
--c               proj doubles as a work array in the present routine, so
--c               proj must be at least m+(krank+3)*n complex*16 elements
--c               long
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c               proj must be at least m+(krank+3)*n complex*16 elements
--c               long.
--c
--c       reference:
--c       Halko, Martinsson, Tropp, "Finding structure with randomness:
--c            probabilistic algorithms for constructing approximate
--c            matrix decompositions," SIAM Review, 53 (2): 217-288,
--c            2011.
--c
--        implicit none
--        integer m,n,krank,list(n),lw,ix,lx,iy,ly,ir,lr
--        complex*16 p1,p2,p3,p4,proj(m+(krank+3)*n)
--        external matveca
--c
--c
--c       Allocate memory in w.
--c
--        lw = 0
--c
--        ir = lw+1
--        lr = (krank+2)*n
--        lw = lw+lr
--c
--        ix = lw+1
--        lx = m
--        lw = lw+lx
--c
--        iy = lw+1
--        ly = n
--        lw = lw+ly
--c
--c
--        call idzr_ridall0(m,n,matveca,p1,p2,p3,p4,krank,
--     1                    list,proj(ir),proj(ix),proj(iy))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzr_ridall0(m,n,matveca,p1,p2,p3,p4,krank,
--     1                          list,r,x,y)
--c
--c       routine idzr_ridall serves as a memory wrapper
--c       for the present routine
--c       (see idzr_ridall for further documentation).
--c
--        implicit none
--        integer j,k,l,m,n,krank,list(n),m2
--        complex*16 x(m),y(n),p1,p2,p3,p4,r(krank+2,n)
--        external matveca
--c
--c
--c       Set the number of random test vectors to 2 more than the rank.
--c
--        l = krank+2
--c
--c       Apply the adjoint of the original matrix to l random vectors.
--c
--        do j = 1,l
--c
--c         Generate a random vector.
--c
--          m2 = m*2
--          call id_srand(m2,x)
--c
--c         Apply the adjoint of the matrix to x, obtaining y.
--c
--          call matveca(m,x,n,y,p1,p2,p3,p4)
--c
--c         Copy the conjugate of y into row j of r.
--c
--          do k = 1,n
--            r(j,k) = conjg(y(k))
--          enddo ! k
--c
--        enddo ! j
--c
--c
--c       ID r.
--c
--        call idzr_id(l,n,r,krank,list,y)
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/idzr_rsvd.f b/scipy/linalg/src/id_dist/src/idzr_rsvd.f
-deleted file mode 100644
-index d788e219b..000000000
---- a/scipy/linalg/src/id_dist/src/idzr_rsvd.f
-+++ /dev/null
-@@ -1,159 +0,0 @@
--c       this file contains the following user-callable routines:
--c
--c
--c       routine idzr_rsvd computes the SVD, to a specified rank,
--c       of a matrix specified by routines for applying the matrix
--c       and its adjoint to arbitrary vectors.
--c       This routine is randomized.
--c
--c
--ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
--c
--c
--c
--c
--        subroutine idzr_rsvd(m,n,matveca,p1t,p2t,p3t,p4t,
--     1                       matvec,p1,p2,p3,p4,krank,u,v,s,ier,w)
--c
--c       constructs a rank-krank SVD  u diag(s) v^*  approximating a,
--c       where matveca is a routine which applies a^*
--c       to an arbitrary vector, and matvec is a routine
--c       which applies a to an arbitrary vector;
--c       u is an m x krank matrix whose columns are orthonormal,
--c       v is an n x krank matrix whose columns are orthonormal,
--c       and diag(s) is a diagonal krank x krank matrix whose entries
--c       are all nonnegative. This routine uses a randomized algorithm.
--c
--c       input:
--c       m -- number of rows in a
--c       n -- number of columns in a
--c       matveca -- routine which applies the adjoint
--c                  of the matrix to be SVD'd
--c                  to an arbitrary vector; this routine must have
--c                  a calling sequence of the form
--c
--c                  matveca(m,x,n,y,p1t,p2t,p3t,p4t),
--c
--c                  where m is the length of x,
--c                  x is the vector to which the adjoint
--c                  of the matrix is to be applied,
--c                  n is the length of y,
--c                  y is the product of the adjoint of the matrix and x,
--c                  and p1t, p2t, p3t, and p4t are user-specified
--c                  parameters
--c       p1t -- parameter to be passed to routine matveca
--c       p2t -- parameter to be passed to routine matveca
--c       p3t -- parameter to be passed to routine matveca
--c       p4t -- parameter to be passed to routine matveca
--c       matvec -- routine which applies the matrix to be SVD'd
--c                 to an arbitrary vector; this routine must have
--c                 a calling sequence of the form
--c
--c                 matvec(n,x,m,y,p1,p2,p3,p4),
--c
--c                 where n is the length of x,
--c                 x is the vector to which the matrix is to be applied,
--c                 m is the length of y,
--c                 y is the product of the matrix and x,
--c                 and p1, p2, p3, and p4 are user-specified parameters
--c       p1 -- parameter to be passed to routine matvec
--c       p2 -- parameter to be passed to routine matvec
--c       p3 -- parameter to be passed to routine matvec
--c       p4 -- parameter to be passed to routine matvec
--c       krank -- rank of the SVD being constructed
--c
--c       output:
--c       u -- matrix of orthonormal left singular vectors of a
--c       v -- matrix of orthonormal right singular vectors of a
--c       s -- array of singular values of a
--c       ier -- 0 when the routine terminates successfully;
--c              nonzero otherwise
--c
--c       work:
--c       w -- must be at least (krank+1)*(2*m+4*n+10)+8*krank**2
--c            complex*16 elements long
--c
--c       _N.B._: The algorithm used by this routine is randomized.
--c
--        implicit none
--        integer m,n,krank,lw,ilist,llist,iproj,lproj,icol,lcol,
--     1          iwork,lwork,ier
--        real*8 s(krank)
--        complex*16 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
--     1             w((krank+1)*(2*m+4*n+10)+8*krank**2)
--        external matveca,matvec
--c
--c
--c       Allocate memory in w.
--c
--        lw = 0
--c
--        ilist = lw+1
--        llist = n
--        lw = lw+llist
--c
--        iproj = lw+1
--        lproj = krank*(n-krank)
--        lw = lw+lproj
--c
--        icol = lw+1
--        lcol = m*krank
--        lw = lw+lcol
--c
--        iwork = lw+1
--        lwork = (krank+1)*(m+3*n+10)+9*krank**2
--        lw = lw+lwork
--c
--c
--        call idzr_rsvd0(m,n,matveca,p1t,p2t,p3t,p4t,
--     1                  matvec,p1,p2,p3,p4,krank,u,v,s,ier,
--     2                  w(ilist),w(iproj),w(icol),w(iwork))
--c
--c
--        return
--        end
--c
--c
--c
--c
--        subroutine idzr_rsvd0(m,n,matveca,p1t,p2t,p3t,p4t,
--     1                        matvec,p1,p2,p3,p4,krank,u,v,s,ier,
--     2                        list,proj,col,work)
--c
--c       routine idzr_rsvd serves as a memory wrapper
--c       for the present routine (please see routine idzr_rsvd
--c       for further documentation).
--c
--        implicit none
--        integer m,n,krank,list(n),ier,k
--        real*8 s(krank)
--        complex*16 p1t,p2t,p3t,p4t,p1,p2,p3,p4,u(m,krank),v(n,krank),
--     1             proj(krank*(n-krank)),col(m*krank),
--     2             work((krank+1)*(m+3*n+10)+9*krank**2)
--        external matveca,matvec
--c
--c
--c       ID a.
--c
--        call idzr_rid(m,n,matveca,p1t,p2t,p3t,p4t,krank,list,work)
--c
--c
--c       Retrieve proj from work.
--c
--        do k = 1,krank*(n-krank)
--          proj(k) = work(k)
--        enddo ! k
--c
--c
--c       Collect together the columns of a indexed by list into col.
--c
--        call idz_getcols(m,n,matvec,p1,p2,p3,p4,krank,list,col,work)
--c
--c
--c       Convert the ID to an SVD.
--c
--        call idz_id2svd(m,krank,col,n,list,proj,u,v,s,ier,work)
--c
--c
--        return
--        end
-diff --git a/scipy/linalg/src/id_dist/src/prini.f b/scipy/linalg/src/id_dist/src/prini.f
-deleted file mode 100644
-index 679590d84..000000000
---- a/scipy/linalg/src/id_dist/src/prini.f
-+++ /dev/null
-@@ -1,113 +0,0 @@
--C
--C
--C
--C
--        SUBROUTINE PRINI(IP1,IQ1)
--        save
--        CHARACTER *1 MES(1), AA(1)
--        REAL *4 A(1)
--        REAL *8 A2(1)
--        REAL *8 A4(1)
--        INTEGER *4 IA(1)
--        INTEGER *2 IA2(1)
--        IP=IP1
--        IQ=IQ1
--
--        RETURN
--  
--C
--C
--C
--C
--C
--        ENTRY PRIN(MES,A,N)
--        CALL  MESSPR(MES,IP,IQ)
--        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1200)(A(J),J=1,N)
--        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1200)(A(J),J=1,N)
-- 1200 FORMAT(6(2X,E11.5))
--         RETURN
--C
--C
--C
--C
--        ENTRY PRIN2(MES,A2,N)
--        CALL MESSPR(MES,IP,IQ)
--        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1400)(A2(J),J=1,N)
--        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1400)(A2(J),J=1,N)
-- 1400 FORMAT(6(2X,E11.5))
--        RETURN
--C
--C
--C
--C
--        ENTRY PRIN2_long(MES,A2,N)
--        CALL MESSPR(MES,IP,IQ)
--        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1450)(A2(J),J=1,N)
--        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1450)(A2(J),J=1,N)
-- 1450 FORMAT(2(2X,E22.16))
--        RETURN
--C
--C
--C
--C
--        ENTRY PRINQ(MES,A4,N)
--        CALL MESSPR(MES,IP,IQ)
--        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1500)(A4(J),J=1,N)
--        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1500)(A4(J),J=1,N)
-- 1500 FORMAT(6(2X,e11.5))
--        RETURN
--C
--C
--C
--C
--        ENTRY PRINF(MES,IA,N)
--        CALL MESSPR(MES,IP,IQ)
--        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1600)(IA(J),J=1,N)
--        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1600)(IA(J),J=1,N)
-- 1600 FORMAT(10(1X,I7))
--        RETURN
--C
--C
--C
--C
--        ENTRY PRINF2(MES,IA2,N)
--        CALL MESSPR(MES,IP,IQ)
--        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,1600)(IA2(J),J=1,N)
--        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,1600)(IA2(J),J=1,N)
--        RETURN
--C
--C
--C
--C
--        ENTRY PRINA(MES,AA,N)
--        CALL MESSPR(MES,IP,IQ)
-- 2000 FORMAT(1X,80A1)
--        IF(IP.NE.0 .AND. N.NE.0) WRITE(IP,2000)(AA(J),J=1,N)
--        IF(IQ.NE.0 .AND. N.NE.0) WRITE(IQ,2000)(AA(J),J=1,N)
--        RETURN
--        END
--c
--c
--c
--c
--c
--        SUBROUTINE MESSPR(MES,IP,IQ)
--        save
--        CHARACTER *1 MES(1),AST
--        DATA AST/'*'/
--C
--C         DETERMINE THE LENGTH OF THE MESSAGE
--C
--        I1=0
--        DO 1400 I=1,10000
--        IF(MES(I).EQ.AST) GOTO 1600
--        I1=I
-- 1400 CONTINUE
-- 1600 CONTINUE
--         IF ( (I1.NE.0) .AND. (IP.NE.0) )
--     1     WRITE(IP,1800) (MES(I),I=1,I1)
--         IF ( (I1.NE.0) .AND. (IQ.NE.0) )
--     1     WRITE(IQ,1800) (MES(I),I=1,I1)
-- 1800 FORMAT(1X,80A1)
--         RETURN
--         END
-diff --git a/scipy/linalg/tests/test_interpolative.py b/scipy/linalg/tests/test_interpolative.py
-index ddc56f7c7..95b83dfad 100644
---- a/scipy/linalg/tests/test_interpolative.py
-+++ b/scipy/linalg/tests/test_interpolative.py
-@@ -1,4 +1,4 @@
--#******************************************************************************
-+#  ******************************************************************************
- #   Copyright (C) 2013 Kenneth L. Ho
- #   Redistribution and use in source and binary forms, with or without
- #   modification, are permitted provided that the following conditions are met:
-@@ -24,7 +24,7 @@
- #   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- #   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- #   POSSIBILITY OF SUCH DAMAGE.
--#******************************************************************************
-+#  ******************************************************************************
- 
- import scipy.linalg.interpolative as pymatrixid
- import numpy as np
-@@ -36,8 +36,6 @@ from numpy.testing import (assert_, assert_allclose, assert_equal,
-                            assert_array_equal)
- import pytest
- from pytest import raises as assert_raises
--import sys
--_IS_32BIT = (sys.maxsize < 2**32)
- 
- 
- @pytest.fixture()
-@@ -45,6 +43,12 @@ def eps():
-     yield 1e-12
- 
- 
-+@pytest.fixture()
-+def rng():
-+    rng = np.random.default_rng(1718313768084012)
-+    yield rng
-+
-+
- @pytest.fixture(params=[np.float64, np.complex128])
- def A(request):
-     # construct Hilbert matrix
-@@ -73,36 +77,32 @@ class TestInterpolativeDecomposition:
-     @pytest.mark.parametrize(
-         "rand,lin_op",
-         [(False, False), (True, False), (True, True)])
--    def test_real_id_fixed_precision(self, A, L, eps, rand, lin_op):
--        if _IS_32BIT and A.dtype == np.complex128 and rand:
--            pytest.xfail("bug in external fortran code")
-+    def test_real_id_fixed_precision(self, A, L, eps, rand, lin_op, rng):
-         # Test ID routines on a Hilbert matrix.
-         A_or_L = A if not lin_op else L
- 
--        k, idx, proj = pymatrixid.interp_decomp(A_or_L, eps, rand=rand)
-+        k, idx, proj = pymatrixid.interp_decomp(A_or_L, eps, rand=rand, rng=rng)
-         B = pymatrixid.reconstruct_matrix_from_id(A[:, idx[:k]], idx, proj)
-         assert_allclose(A, B, rtol=eps, atol=1e-08)
- 
-     @pytest.mark.parametrize(
-         "rand,lin_op",
-         [(False, False), (True, False), (True, True)])
--    def test_real_id_fixed_rank(self, A, L, eps, rank, rand, lin_op):
--        if _IS_32BIT and A.dtype == np.complex128 and rand:
--            pytest.xfail("bug in external fortran code")
-+    def test_real_id_fixed_rank(self, A, L, eps, rank, rand, lin_op, rng):
-         k = rank
-         A_or_L = A if not lin_op else L
- 
--        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand)
-+        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand, rng=rng)
-         B = pymatrixid.reconstruct_matrix_from_id(A[:, idx[:k]], idx, proj)
-         assert_allclose(A, B, rtol=eps, atol=1e-08)
- 
-     @pytest.mark.parametrize("rand,lin_op", [(False, False)])
-     def test_real_id_skel_and_interp_matrices(
--            self, A, L, eps, rank, rand, lin_op):
-+            self, A, L, eps, rank, rand, lin_op, rng):
-         k = rank
-         A_or_L = A if not lin_op else L
- 
--        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand)
-+        idx, proj = pymatrixid.interp_decomp(A_or_L, k, rand=rand, rng=rng)
-         P = pymatrixid.reconstruct_interp_matrix(idx, proj)
-         B = pymatrixid.reconstruct_skel_matrix(A, k, idx)
-         assert_allclose(B, A[:, idx[:k]], rtol=eps, atol=1e-08)
-@@ -111,25 +111,21 @@ class TestInterpolativeDecomposition:
-     @pytest.mark.parametrize(
-         "rand,lin_op",
-         [(False, False), (True, False), (True, True)])
--    def test_svd_fixed_precison(self, A, L, eps, rand, lin_op):
--        if _IS_32BIT and A.dtype == np.complex128 and rand:
--            pytest.xfail("bug in external fortran code")
-+    def test_svd_fixed_precision(self, A, L, eps, rand, lin_op, rng):
-         A_or_L = A if not lin_op else L
- 
--        U, S, V = pymatrixid.svd(A_or_L, eps, rand=rand)
-+        U, S, V = pymatrixid.svd(A_or_L, eps, rand=rand, rng=rng)
-         B = U * S @ V.T.conj()
-         assert_allclose(A, B, rtol=eps, atol=1e-08)
- 
-     @pytest.mark.parametrize(
-         "rand,lin_op",
-         [(False, False), (True, False), (True, True)])
--    def test_svd_fixed_rank(self, A, L, eps, rank, rand, lin_op):
--        if _IS_32BIT and A.dtype == np.complex128 and rand:
--            pytest.xfail("bug in external fortran code")
-+    def test_svd_fixed_rank(self, A, L, eps, rank, rand, lin_op, rng):
-         k = rank
-         A_or_L = A if not lin_op else L
- 
--        U, S, V = pymatrixid.svd(A_or_L, k, rand=rand)
-+        U, S, V = pymatrixid.svd(A_or_L, k, rand=rand, rng=rng)
-         B = U * S @ V.T.conj()
-         assert_allclose(A, B, rtol=eps, atol=1e-08)
- 
-@@ -141,59 +137,39 @@ class TestInterpolativeDecomposition:
-         B = U * S @ V.T.conj()
-         assert_allclose(A, B, rtol=eps, atol=1e-08)
- 
--    def test_estimate_spectral_norm(self, A):
-+    def test_estimate_spectral_norm(self, A, rng):
-         s = svdvals(A)
--        norm_2_est = pymatrixid.estimate_spectral_norm(A)
-+        norm_2_est = pymatrixid.estimate_spectral_norm(A, rng=rng)
-         assert_allclose(norm_2_est, s[0], rtol=1e-6, atol=1e-8)
- 
--    def test_estimate_spectral_norm_diff(self, A):
-+    def test_estimate_spectral_norm_diff(self, A, rng):
-         B = A.copy()
-         B[:, 0] *= 1.2
-         s = svdvals(A - B)
--        norm_2_est = pymatrixid.estimate_spectral_norm_diff(A, B)
-+        norm_2_est = pymatrixid.estimate_spectral_norm_diff(A, B, rng=rng)
-         assert_allclose(norm_2_est, s[0], rtol=1e-6, atol=1e-8)
- 
--    def test_rank_estimates_array(self, A):
-+    def test_rank_estimates_array(self, A, rng):
-         B = np.array([[1, 1, 0], [0, 0, 1], [0, 0, 1]], dtype=A.dtype)
- 
-         for M in [A, B]:
-             rank_tol = 1e-9
-             rank_np = np.linalg.matrix_rank(M, norm(M, 2) * rank_tol)
--            rank_est = pymatrixid.estimate_rank(M, rank_tol)
-+            rank_est = pymatrixid.estimate_rank(M, rank_tol, rng=rng)
-             assert_(rank_est >= rank_np)
-             assert_(rank_est <= rank_np + 10)
- 
--    def test_rank_estimates_lin_op(self, A):
-+    def test_rank_estimates_lin_op(self, A, rng):
-         B = np.array([[1, 1, 0], [0, 0, 1], [0, 0, 1]], dtype=A.dtype)
- 
-         for M in [A, B]:
-             ML = aslinearoperator(M)
-             rank_tol = 1e-9
-             rank_np = np.linalg.matrix_rank(M, norm(M, 2) * rank_tol)
--            rank_est = pymatrixid.estimate_rank(ML, rank_tol)
-+            rank_est = pymatrixid.estimate_rank(ML, rank_tol, rng=rng)
-             assert_(rank_est >= rank_np - 4)
-             assert_(rank_est <= rank_np + 4)
- 
--    def test_rand(self):
--        pymatrixid.seed('default')
--        assert_allclose(pymatrixid.rand(2), [0.8932059, 0.64500803],
--                        rtol=1e-4, atol=1e-8)
--
--        pymatrixid.seed(1234)
--        x1 = pymatrixid.rand(2)
--        assert_allclose(x1, [0.7513823, 0.06861718], rtol=1e-4, atol=1e-8)
--
--        np.random.seed(1234)
--        pymatrixid.seed()
--        x2 = pymatrixid.rand(2)
--
--        np.random.seed(1234)
--        pymatrixid.seed(np.random.rand(55))
--        x3 = pymatrixid.rand(2)
--
--        assert_allclose(x1, x2)
--        assert_allclose(x1, x3)
--
-     def test_badcall(self):
-         A = hilbert(5).astype(np.float32)
-         with assert_raises(ValueError):
-@@ -228,8 +204,6 @@ class TestInterpolativeDecomposition:
-     @pytest.mark.parametrize("rand", [True, False])
-     @pytest.mark.parametrize("eps", [1, 0.1])
-     def test_bug_9793(self, dtype, rand, eps):
--        if _IS_32BIT and dtype == np.complex128 and rand:
--            pytest.xfail("bug in external fortran code")
-         A = np.array([[-1, -1, -1, 0, 0, 0],
-                       [0, 0, 0, 1, 1, 1],
-                       [1, 0, 0, 1, 0, 0],
--- 
-2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch b/integration_tests/recipes/scipy/patches/0007-Remove-chla_transtype.patch
similarity index 89%
rename from integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch
rename to integration_tests/recipes/scipy/patches/0007-Remove-chla_transtype.patch
index c4afc190..7e6af9d8 100644
--- a/integration_tests/recipes/scipy/patches/0012-Remove-chla_transtype.patch
+++ b/integration_tests/recipes/scipy/patches/0007-Remove-chla_transtype.patch
@@ -1,27 +1,27 @@
-From 848c94e218e89d866978fbc883cbb2d919f56ce9 Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Wed, 31 Jul 2024 10:29:47 +0200
-Subject: [PATCH 12/18] Remove chla_transtype
-
-The signature should probably be `int chla_transtype(char* res, int *trans)`.
-This just deletes it entirely due to laziness.
-
----
- scipy/linalg/cython_lapack_signatures.txt | 1 -
- 1 file changed, 1 deletion(-)
-
-diff --git a/scipy/linalg/cython_lapack_signatures.txt b/scipy/linalg/cython_lapack_signatures.txt
-index 1f3dc226ab..28aa8b8c22 100644
---- a/scipy/linalg/cython_lapack_signatures.txt
-+++ b/scipy/linalg/cython_lapack_signatures.txt
-@@ -108,7 +108,6 @@ void chetrs(char *uplo, int *n, int *nrhs, c *a, int *lda, int *ipiv, c *b, int
- void chetrs2(char *uplo, int *n, int *nrhs, c *a, int *lda, int *ipiv, c *b, int *ldb, c *work, int *info)
- void chfrk(char *transr, char *uplo, char *trans, int *n, int *k, s *alpha, c *a, int *lda, s *beta, c *c)
- void chgeqz(char *job, char *compq, char *compz, int *n, int *ilo, int *ihi, c *h, int *ldh, c *t, int *ldt, c *alpha, c *beta, c *q, int *ldq, c *z, int *ldz, c *work, int *lwork, s *rwork, int *info)
--char chla_transtype(int *trans)
- void chpcon(char *uplo, int *n, c *ap, int *ipiv, s *anorm, s *rcond, c *work, int *info)
- void chpev(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, s *rwork, int *info)
- void chpevd(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, int *lwork, s *rwork, int *lrwork, int *iwork, int *liwork, int *info)
--- 
-2.39.3 (Apple Git-146)
-
+From 848c94e218e89d866978fbc883cbb2d919f56ce9 Mon Sep 17 00:00:00 2001
+From: Hood Chatham 
+Date: Wed, 31 Jul 2024 10:29:47 +0200
+Subject: [PATCH 07/11] Remove chla_transtype
+
+The signature should probably be `int chla_transtype(char* res, int *trans)`.
+This just deletes it entirely due to laziness.
+
+---
+ scipy/linalg/cython_lapack_signatures.txt | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/scipy/linalg/cython_lapack_signatures.txt b/scipy/linalg/cython_lapack_signatures.txt
+index 5aa59d96ea..afdc9480f1 100644
+--- a/scipy/linalg/cython_lapack_signatures.txt
++++ b/scipy/linalg/cython_lapack_signatures.txt
+@@ -111,7 +111,6 @@ void chetrs(char *uplo, int *n, int *nrhs, c *a, int *lda, int *ipiv, c *b, int
+ void chetrs2(char *uplo, int *n, int *nrhs, c *a, int *lda, int *ipiv, c *b, int *ldb, c *work, int *info)
+ void chfrk(char *transr, char *uplo, char *trans, int *n, int *k, s *alpha, c *a, int *lda, s *beta, c *c)
+ void chgeqz(char *job, char *compq, char *compz, int *n, int *ilo, int *ihi, c *h, int *ldh, c *t, int *ldt, c *alpha, c *beta, c *q, int *ldq, c *z, int *ldz, c *work, int *lwork, s *rwork, int *info)
+-char chla_transtype(int *trans)
+ void chpcon(char *uplo, int *n, c *ap, int *ipiv, s *anorm, s *rcond, c *work, int *info)
+ void chpev(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, s *rwork, int *info)
+ void chpevd(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, int *lwork, s *rwork, int *lrwork, int *iwork, int *liwork, int *info)
+-- 
+2.39.3 (Apple Git-146)
+
diff --git a/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch b/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
deleted file mode 100644
index 705d648d..00000000
--- a/integration_tests/recipes/scipy/patches/0008-Mark-mvndst-functions-recursive.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From c11745d763407d9a2bb195a21e2a8afaf7635248 Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Sat, 6 Jul 2024 22:38:55 +0200
-Subject: [PATCH 8/18] Mark mvndst functions recursive
-
----
- scipy/stats/mvndst.f | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/scipy/stats/mvndst.f b/scipy/stats/mvndst.f
-index 41afa7e74..5065a15ff 100644
---- a/scipy/stats/mvndst.f
-+++ b/scipy/stats/mvndst.f
-@@ -21,8 +21,8 @@
- *          Pullman, WA 99164-3113
- *          Email : alangenz@wsu.edu
- *
--      SUBROUTINE mvnun(d, n, lower, upper, means, covar, maxpts, 
--     &                   abseps, releps, value, inform)
-+      RECURSIVE SUBROUTINE mvnun(d, n, lower, upper, means, covar, 
-+     &                   maxpts, abseps, releps, value, inform)
- *  Parameters
- *
- *   d       integer, dimensionality of the data
-@@ -88,8 +88,8 @@
-       END 
- 
- 
--      SUBROUTINE mvnun_weighted(d, n, lower, upper, means, weights,
--     &                          covar, maxpts, abseps, releps, 
-+      recursive SUBROUTINE mvnun_weighted(d, n, lower, upper, means, 
-+     &                          weights, covar, maxpts, abseps, releps,
-      &                           value, inform)
- *  Parameters
- *
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch b/integration_tests/recipes/scipy/patches/0008-Set-wrapper-return-type-to-int.patch
similarity index 94%
rename from integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch
rename to integration_tests/recipes/scipy/patches/0008-Set-wrapper-return-type-to-int.patch
index c20be03f..70cd53dd 100644
--- a/integration_tests/recipes/scipy/patches/0013-Set-wrapper-return-type-to-int.patch
+++ b/integration_tests/recipes/scipy/patches/0008-Set-wrapper-return-type-to-int.patch
@@ -1,7 +1,7 @@
 From b5d05197de084ab3cab52241f163bae7519b6027 Mon Sep 17 00:00:00 2001
 From: Hood Chatham 
 Date: Wed, 31 Jul 2024 11:48:12 +0200
-Subject: [PATCH 13/18] Set wrapper return type to int
+Subject: [PATCH 08/11] Set wrapper return type to int
 
 ---
  scipy/linalg/_generate_pyx.py | 2 +-
diff --git a/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch b/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
deleted file mode 100644
index 0ca5929f..00000000
--- a/integration_tests/recipes/scipy/patches/0009-Make-sreorth-recursive.patch
+++ /dev/null
@@ -1,111 +0,0 @@
-From e4d1a570fa8bd4c710e10400822f60232e6408eb Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Sat, 6 Jul 2024 22:33:51 +0200
-Subject: [PATCH 9/18] Make sreorth recursive
-
----
- complex16/zreorth.F | 6 +++---
- complex8/creorth.F  | 6 +++---
- double/dreorth.F    | 6 +++---
- single/sreorth.F    | 6 +++---
- 4 files changed, 12 insertions(+), 12 deletions(-)
-
-diff --git a/scipy/sparse/linalg/_propack/PROPACK/complex16/zreorth.F b/scipy/sparse/linalg/_propack/PROPACK/complex16/zreorth.F
-index ca74f7a..c447a6a 100644
---- a/scipy/sparse/linalg/_propack/PROPACK/complex16/zreorth.F
-+++ b/scipy/sparse/linalg/_propack/PROPACK/complex16/zreorth.F
-@@ -2,8 +2,8 @@ c
- c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
- c
- 
--      subroutine zreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
--     c     iflag)
-+      recursive subroutine zreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
-+     c  work, iflag)
- c
- c     Orthogonalize the N-vector VNEW against a subset of the columns of
- c     the N-by-K matrix V(1:N,1:K) using iterated classical or modified
-@@ -103,7 +103,7 @@ c
- c****************************************************************************
- c
- 
--      subroutine zcgs(n,k,V,ldv,vnew,index,work)
-+      recursive subroutine zcgs(n,k,V,ldv,vnew,index,work)
- 
- c     Block  Gram-Schmidt orthogonalization:
- c     FOR i= 1:l
-diff --git a/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F b/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F
-index cd87247..e657a89 100644
---- a/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F
-+++ b/scipy/sparse/linalg/_propack/PROPACK/complex8/creorth.F
-@@ -2,8 +2,8 @@ c
- c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
- c
- 
--      subroutine creorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
--     c     iflag)
-+      recursive subroutine creorth(n,k,V,ldv,vnew,normvnew,index,alpha,
-+     c  work, iflag)
- c
- c     Orthogonalize the N-vector VNEW against a subset of the columns of
- c     the N-by-K matrix V(1:N,1:K) using iterated classical or modified
-@@ -103,7 +103,7 @@ c
- c****************************************************************************
- c
- 
--      subroutine ccgs(n,k,V,ldv,vnew,index,work)
-+      recursive subroutine ccgs(n,k,V,ldv,vnew,index,work)
- 
- c     Block  Gram-Schmidt orthogonalization:
- c     FOR i= 1:l
-diff --git a/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F b/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F
-index 841208a..fec923e 100644
---- a/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F
-+++ b/scipy/sparse/linalg/_propack/PROPACK/double/dreorth.F
-@@ -2,8 +2,8 @@ c
- c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
- c
- 
--      subroutine dreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
--     c     iflag)
-+      recursive subroutine dreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
-+     c  work, iflag)
- c
- c     Orthogonalize the N-vector VNEW against a subset of the columns of
- c     the N-by-K matrix V(1:N,1:K) using iterated classical or modified
-@@ -103,7 +103,7 @@ c
- c****************************************************************************
- c
- 
--      subroutine dcgs(n,k,V,ldv,vnew,index,work)
-+      recursive subroutine dcgs(n,k,V,ldv,vnew,index,work)
- 
- c     Block  Gram-Schmidt orthogonalization:
- c     FOR i= 1:l
-diff --git a/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F b/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F
-index 644d404..61b6698 100644
---- a/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F
-+++ b/scipy/sparse/linalg/_propack/PROPACK/single/sreorth.F
-@@ -2,8 +2,8 @@ c
- c     Rasmus Munk Larsen, Stanford University, 1999, 2004.
- c
- 
--      subroutine sreorth(n,k,V,ldv,vnew,normvnew,index,alpha,work,
--     c     iflag)
-+      recursive subroutine sreorth(n,k,V,ldv,vnew,normvnew,index,alpha,
-+     c  work, iflag)
- c
- c     Orthogonalize the N-vector VNEW against a subset of the columns of
- c     the N-by-K matrix V(1:N,1:K) using iterated classical or modified
-@@ -103,7 +103,7 @@ c
- c****************************************************************************
- c
- 
--      subroutine scgs(n,k,V,ldv,vnew,index,work)
-+      recursive subroutine scgs(n,k,V,ldv,vnew,index,work)
- 
- c     Block  Gram-Schmidt orthogonalization:
- c     FOR i= 1:l
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0010-Explicitly-convert-return-value-of-SUPERLU_MALLOC.patch b/integration_tests/recipes/scipy/patches/0010-Explicitly-convert-return-value-of-SUPERLU_MALLOC.patch
new file mode 100644
index 00000000..246ac536
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0010-Explicitly-convert-return-value-of-SUPERLU_MALLOC.patch
@@ -0,0 +1,76 @@
+From 6a800412b14b5ab905721abe9a509a5e4f44ecef Mon Sep 17 00:00:00 2001
+From: ryanking13 
+Date: Tue, 20 Jan 2026 15:22:19 +0900
+Subject: [PATCH 10/11] Explicitly convert return value of SUPERLU_MALLOC
+
+Fixes incompatible pointer type errors like:
+
+```
+error: incompatible pointer types assigning to 'float *' from 'int *' [-Wincompatible-pointer-types]
+```
+
+Upstream PR:
+https://github.com/scipy/scipy/pull/24408
+
+---
+ scipy/sparse/linalg/_dsolve/SuperLU/SRC/cgsitrf.c | 2 +-
+ scipy/sparse/linalg/_dsolve/SuperLU/SRC/dgsitrf.c | 2 +-
+ scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgsitrf.c | 2 +-
+ scipy/sparse/linalg/_dsolve/SuperLU/SRC/zgsitrf.c | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/cgsitrf.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/cgsitrf.c
+index 21fb2497b..ae2a3fd2e 100644
+--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/cgsitrf.c
++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/cgsitrf.c
+@@ -299,7 +299,7 @@ cgsitrf(superlu_options_t *options, SuperMatrix *A, int relax, int panel_size,
+     for (k = 0; k < n; k++) iswap[k] = perm_c[k];
+     amax = (float *) SUPERLU_MALLOC(panel_size * sizeof(float));
+     if (drop_rule & DROP_SECONDARY)
+-	swork2 = SUPERLU_MALLOC(n * sizeof(float));
++	swork2 = (float *) SUPERLU_MALLOC(n * sizeof(float));
+     else
+ 	swork2 = NULL;
+ 
+diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/dgsitrf.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/dgsitrf.c
+index b3c1ffc15..57f242361 100644
+--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/dgsitrf.c
++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/dgsitrf.c
+@@ -298,7 +298,7 @@ dgsitrf(superlu_options_t *options, SuperMatrix *A, int relax, int panel_size,
+     for (k = 0; k < n; k++) iswap[k] = perm_c[k];
+     amax = (double *) SUPERLU_MALLOC(panel_size * sizeof(double));
+     if (drop_rule & DROP_SECONDARY)
+-	dwork2 = SUPERLU_MALLOC(n * sizeof(double));
++	dwork2 = (double *) SUPERLU_MALLOC(n * sizeof(double));
+     else
+ 	dwork2 = NULL;
+ 
+diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgsitrf.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgsitrf.c
+index cc143726f..5c9722c45 100644
+--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgsitrf.c
++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgsitrf.c
+@@ -298,7 +298,7 @@ sgsitrf(superlu_options_t *options, SuperMatrix *A, int relax, int panel_size,
+     for (k = 0; k < n; k++) iswap[k] = perm_c[k];
+     amax = (float *) SUPERLU_MALLOC(panel_size * sizeof(float));
+     if (drop_rule & DROP_SECONDARY)
+-	swork2 = SUPERLU_MALLOC(n * sizeof(float));
++	swork2 = (float *) SUPERLU_MALLOC(n * sizeof(float));
+     else
+ 	swork2 = NULL;
+ 
+diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/zgsitrf.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/zgsitrf.c
+index 4658eaf4c..a60c8119b 100644
+--- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/zgsitrf.c
++++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/zgsitrf.c
+@@ -299,7 +299,7 @@ zgsitrf(superlu_options_t *options, SuperMatrix *A, int relax, int panel_size,
+     for (k = 0; k < n; k++) iswap[k] = perm_c[k];
+     amax = (double *) SUPERLU_MALLOC(panel_size * sizeof(double));
+     if (drop_rule & DROP_SECONDARY)
+-	dwork2 = SUPERLU_MALLOC(n * sizeof(double));
++	dwork2 = (double *) SUPERLU_MALLOC(n * sizeof(double));
+     else
+ 	dwork2 = NULL;
+ 
+-- 
+2.29.2.windows.2
+
diff --git a/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch b/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
deleted file mode 100644
index ad975ccd..00000000
--- a/integration_tests/recipes/scipy/patches/0010-Link-openblas-with-modules-that-require-f2c.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From ccbb0fa0884d567c6139eeed7dc2dc9f8db4db3a Mon Sep 17 00:00:00 2001
-From: ryanking13 
-Date: Sun, 28 Jul 2024 18:15:17 +0900
-Subject: [PATCH 10/18] Link openblas with modules that require f2c
-
-Some fortran modules require symbols from f2c, which is provided by
-openblas.
-This patch adds openblas as a dependency to the modules that require f2c
-symbols.
-
-Co-Developed-by: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
----
- scipy/integrate/meson.build | 2 +-
- scipy/optimize/meson.build  | 6 +++---
- scipy/stats/meson.build     | 2 +-
- 3 files changed, 5 insertions(+), 5 deletions(-)
-
-diff --git a/scipy/integrate/meson.build b/scipy/integrate/meson.build
-index 23a715dd58..e5cd9ad4c8 100644
---- a/scipy/integrate/meson.build
-+++ b/scipy/integrate/meson.build
-@@ -154,7 +154,7 @@ py3.extension_module('_dop',
-   f2py_gen.process('dop.pyf'),
-   link_with: [dop_lib],
-   c_args: [Wno_unused_variable],
--  dependencies: [fortranobject_dep],
-+  dependencies: [lapack, fortranobject_dep],
-   link_args: version_link_args,
-   install: true,
-   link_language: 'fortran',
-diff --git a/scipy/optimize/meson.build b/scipy/optimize/meson.build
-index d6c20d3d53..d7f0284b5b 100644
---- a/scipy/optimize/meson.build
-+++ b/scipy/optimize/meson.build
-@@ -125,7 +125,7 @@ py3.extension_module('_cobyla',
-   c_args: [Wno_unused_variable],
-   fortran_args: fortran_ignore_warnings,
-   link_args: version_link_args,
--  dependencies: [fortranobject_dep],
-+  dependencies: [lapack, fortranobject_dep],
-   install: true,
-   link_language: 'fortran',
-   subdir: 'scipy/optimize'
-@@ -135,7 +135,7 @@ py3.extension_module('_minpack2',
-   [f2py_gen.process('minpack2/minpack2.pyf'), 'minpack2/dcsrch.f', 'minpack2/dcstep.f'],
-   fortran_args: fortran_ignore_warnings,
-   link_args: version_link_args,
--  dependencies: [fortranobject_dep],
-+  dependencies: [lapack, fortranobject_dep],
-   override_options: ['b_lto=false'],
-   install: true,
-   link_language: 'fortran',
-@@ -146,7 +146,7 @@ py3.extension_module('_slsqp',
-   [f2py_gen.process('slsqp/slsqp.pyf'), 'slsqp/slsqp_optmz.f'],
-   fortran_args: fortran_ignore_warnings,
-   link_args: version_link_args,
--  dependencies: [fortranobject_dep],
-+  dependencies: [lapack, fortranobject_dep],
-   install: true,
-   link_language: 'fortran',
-   subdir: 'scipy/optimize'
-diff --git a/scipy/stats/meson.build b/scipy/stats/meson.build
-index bb43e3b2e9..358279a93b 100644
---- a/scipy/stats/meson.build
-+++ b/scipy/stats/meson.build
-@@ -36,7 +36,7 @@ py3.extension_module('_mvn',
-   # Wno-surprising is to suppress a pointless warning with GCC 10-12
-   # (see GCC bug 98411: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98411)
-   fortran_args: [fortran_ignore_warnings, _fflag_Wno_surprising],
--  dependencies: [fortranobject_dep],
-+  dependencies: [lapack, fortranobject_dep],
-   link_args: version_link_args,
-   install: true,
-   link_language: 'fortran',
--- 
-2.39.3 (Apple Git-146)
diff --git a/integration_tests/recipes/scipy/patches/0011-MAINT-linalg-Remove-dummy-argument-from-larf-wrapper.patch b/integration_tests/recipes/scipy/patches/0011-MAINT-linalg-Remove-dummy-argument-from-larf-wrapper.patch
new file mode 100644
index 00000000..6762423f
--- /dev/null
+++ b/integration_tests/recipes/scipy/patches/0011-MAINT-linalg-Remove-dummy-argument-from-larf-wrapper.patch
@@ -0,0 +1,46 @@
+From 5a684821668bcbbd3a4976c91b4967bfdaee2a59 Mon Sep 17 00:00:00 2001
+From: Ilhan Polat 
+Date: Mon, 5 Jan 2026 01:15:17 +0100
+Subject: [PATCH 11/11] MAINT:linalg: Remove dummy larfg parameter
+
+---
+diff --git a/scipy/linalg/flapack_other.pyf.src b/scipy/linalg/flapack_other.pyf.src
+index 1db51bbd83..049344ae5e 100644
+--- a/scipy/linalg/flapack_other.pyf.src
++++ b/scipy/linalg/flapack_other.pyf.src
+@@ -2214,16 +2214,21 @@ function lantr(norm, uplo, diag, m, n, a, lda, work) result(n2)
+ 
+ end function lantr
+ 
+-subroutine larfg(n, alpha, x, incx, tau, lx)
++subroutine larfg(n, alpha, x, incx, tau)
++    callstatement (*f2py_func)(&n,&alpha,x,&incx,&tau)
++    callprotoargument F_INT*, *, *, F_INT*, *
++
+     integer intent(in), check(n>=1) :: n
+      intent(in,out) :: alpha
+-     intent(in,copy,out), dimension(lx) :: x
++     intent(in,copy,out), dimension(1+(n-2)*abs(incx)), depend(n,incx) :: x
+     integer intent(in), check(incx>0||incx<0) :: incx = 1
+      intent(out) :: tau
+-    integer intent(hide),depend(x,n,incx),check(lx > (n-2)*incx) :: lx = len(x)
+ end subroutine larfg
+ 
+-subroutine larf(side,m,n,v,incv,tau,c,ldc,work,lwork)
++subroutine larf(side,m,n,v,incv,tau,c,ldc,work)
++    callstatement (*f2py_func)(&side,&m,&n,v,&incv,&tau,c,&ldc,work)
++    callprotoargument char*, F_INT*, F_INT*, *, F_INT*, *, *, F_INT*, *
++
+     character intent(in), check(side[0]=='L'||side[0]=='R') :: side = 'L'
+     integer intent(in,hide), depend(c) :: m = shape(c,0)
+     integer intent(in,hide), depend(c) :: n = shape(c,1)
+@@ -2233,8 +2238,7 @@ subroutine larf(side,m,n,v,incv,tau,c,ldc,work,lwork)
+      dimension(m,n), intent(in,copy,out) :: c
+     integer intent(in,hide) :: ldc = max(1,shape(c,0))
+     ! FIXME: work should not have been an input argument but kept here for backwards compatibility!
+-     intent(in),dimension(lwork),depend(side,m,n) :: work
+-    integer intent(hide),depend(work),check(lwork >= (side[0]=='L'?n:m)) :: lwork = len(work)
++     intent(in), dimension((side[0]=='L'?n:m)), depend(side,m,n) :: work
+ end subroutine larf
+ 
+ subroutine lartg(f,g,cs,sn,r)
diff --git a/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch b/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
deleted file mode 100644
index 78272f58..00000000
--- a/integration_tests/recipes/scipy/patches/0011-Remove-fpchec-inline-if-then-endif-constructs.patch
+++ /dev/null
@@ -1,94 +0,0 @@
-From b43a231f8326d6953929030131c3fb6b2cb163bd Mon Sep 17 00:00:00 2001
-From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
-Date: Wed, 15 May 2024 21:29:02 +0530
-Subject: [PATCH 11/18] Remove fpchec inline if-then-endif constructs
-
-This PR removes the single-line if-then-endif constructs in fpchec.f
-that were causing syntactical errors when compiling with f2c, possibly
-because fpchec uses some dated, punch-card FORTRAN syntax. It converts
-them to statements split over multiple lines.
-
-This patch has been upstreamed via https://github.com/scipy/scipy/pull/21365
-and it can be safely removed once SciPy v1.15.0 is released and is being
-integrated in Pyodide.
-
----
- scipy/interpolate/fitpack/fpchec.f | 42 +++++++++++++++++++++++-------
- 1 file changed, 32 insertions(+), 10 deletions(-)
-
-diff --git a/scipy/interpolate/fitpack/fpchec.f b/scipy/interpolate/fitpack/fpchec.f
-index 75a58c40ec..215f38f31f 100644
---- a/scipy/interpolate/fitpack/fpchec.f
-+++ b/scipy/interpolate/fitpack/fpchec.f
-@@ -29,36 +29,58 @@ c  ..
-       nk2 = nk1+1
-       ier = 10
- c  check condition no 1
--      if(nk1.lt.k1 .or. nk1.gt.m)then; ier=10; go to 80; endif
-+      if (nk1.lt.k1 .or. nk1.gt.m) then
-+          ier = 10
-+          go to 80
-+      endif
- c  check condition no 2
-       j = n
-       do 20 i=1,k
--        if(t(i).gt.t(i+1))then; ier=20; go to 80; endif
--        if(t(j).lt.t(j-1))then; ier=20; go to 80; endif
-+        if (t(i) .gt. t(i+1)) then
-+            ier = 20
-+            go to 80
-+        endif
-+        if (t(j) .lt. t(j-1)) then
-+            ier = 20
-+            go to 80
-+        endif
-         j = j-1
-   20  continue
- c  check condition no 3
-       do 30 i=k2,nk2
--        if(t(i).le.t(i-1))then; ier=30; go to 80; endif
-+        if (t(i) .le. t(i-1)) then
-+            ier = 30
-+            go to 80
-+        endif
-   30  continue
- c  check condition no 4
--      if(x(1).lt.t(k1) .or. x(m).gt.t(nk2))then; ier=40; go to 80;
-+      if (x(1).lt.t(k1) .or. x(m).gt.t(nk2)) then
-+          ier = 40
-+          go to 80
-       endif
- c  check condition no 5
--      if(x(1).ge.t(k2) .or. x(m).le.t(nk1))then; ier=50; go to 80;
-+      if (x(1).ge.t(k2) .or. x(m).le.t(nk1)) then
-+          ier = 50
-+          go to 80
-       endif
-       i = 1
-       l = k2
-       nk3 = nk1-1
--      if(nk3.lt.2) go to 70
-+      if (nk3 .lt. 2) go to 70
-       do 60 j=2,nk3
-         tj = t(j)
-         l = l+1
-         tl = t(l)
-   40    i = i+1
--        if(i.ge.m)then; ier=50; go to 80; endif
--        if(x(i).le.tj) go to 40
--        if(x(i).ge.tl)then; ier=50; go to 80; endif
-+        if (i .ge. m) then
-+            ier = 50
-+            go to 80
-+        endif
-+        if (x(i) .le. tj) go to 40
-+        if (x(i) .ge. tl) then
-+            ier = 50
-+            go to 80
-+        endif
-   60  continue
-   70  ier = 0
-   80  return
--- 
-2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch b/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
deleted file mode 100644
index b9e521f3..00000000
--- a/integration_tests/recipes/scipy/patches/0014-Skip-svd_gesdd-test.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-From 59d3efdf9e55958c6a3651e8eda2a9d6fe48e192 Mon Sep 17 00:00:00 2001
-From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
-Date: Fri, 9 Aug 2024 19:00:41 +0530
-Subject: [PATCH 14/18] Skip svd_gesdd test
-
-This patch excludes a test for gesdd which was introduced in this PR:
-https://github.com/scipy/scipy/pull/20349. It is not useful for Pyodide
-since it is a memory-intensive test and it is not expected to pass in
-a WASM environment where allocating memory for large arrays is tricky.
-
-This patch has been upstreamed in https://github.com/scipy/scipy/pull/21349
-and it can be safely removed once SciPy v1.15.0 is released and is being
-integrated in Pyodide.
-
----
- scipy/linalg/tests/test_decomp.py | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/scipy/linalg/tests/test_decomp.py b/scipy/linalg/tests/test_decomp.py
-index b43016c027..cbd80252b1 100644
---- a/scipy/linalg/tests/test_decomp.py
-+++ b/scipy/linalg/tests/test_decomp.py
-@@ -1,5 +1,6 @@
- import itertools
- import platform
-+import sys
- 
- import numpy as np
- from numpy.testing import (assert_equal, assert_almost_equal,
-@@ -37,6 +38,8 @@ try:
- except ImportError:
-     CONFIG = None
- 
-+IS_WASM = (sys.platform == "emscripten" or platform.machine() in ["wasm32", "wasm64"])
-+
- 
- def _random_hermitian_matrix(n, posdef=False, dtype=float):
-     "Generate random sym/hermitian array of the given size n"
-@@ -1179,6 +1182,9 @@ class TestSVD_GESVD(TestSVD_GESDD):
-     lapack_driver = 'gesvd'
- 
- 
-+# Allocating an array of such a size leads to _ArrayMemoryError(s)
-+# since the maximum memory that can be in 32-bit (WASM) is 4GB
-+@pytest.mark.skipif(IS_WASM, reason="out of memory in WASM")
- @pytest.mark.fail_slow(5)
- def test_svd_gesdd_nofegfault():
-     # svd(a) with {U,VT}.size > INT_MAX does not segfault
--- 
-2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch b/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
deleted file mode 100644
index a80ca320..00000000
--- a/integration_tests/recipes/scipy/patches/0015-Remove-f2py-generators.patch
+++ /dev/null
@@ -1,304 +0,0 @@
-From 9b670bd5330bd7834d157a9ec3087a97b71d6516 Mon Sep 17 00:00:00 2001
-From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
-Date: Fri, 16 Aug 2024 22:59:26 +0530
-Subject: [PATCH 15/18] Remove f2py generators
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This patch reverts changes made in d85ba6b910ea9040b6a72bdc4ea87d151118f41d
-and is applied at the end, after the rest of the patches – the order is important.
-
-It removes the f2py generator and replaces it with custom targets mapping to
-f2py-generated wrappers. This is done to avoid the need for the f2py executable
-to be present in the environment where SciPy is built. Instead, the Python
-executable is used to run f2py as a module which is useful where f2py is not
-present on PATH.
-
----
- scipy/integrate/meson.build              | 32 +++++++++++++++++++++---
- scipy/interpolate/meson.build            |  8 +++++-
- scipy/io/meson.build                     |  8 +++++-
- scipy/meson.build                        | 24 ------------------
- scipy/optimize/meson.build               | 30 +++++++++++++++++++---
- scipy/sparse/linalg/_propack/meson.build |  8 +++++-
- scipy/stats/meson.build                  |  8 +++++-
- tools/generate_f2pymod.py                |  3 ++-
- 8 files changed, 85 insertions(+), 36 deletions(-)
-
-diff --git a/scipy/integrate/meson.build b/scipy/integrate/meson.build
-index cfaa927139..44c63fa526 100644
---- a/scipy/integrate/meson.build
-+++ b/scipy/integrate/meson.build
-@@ -128,8 +128,14 @@ py3.extension_module('_odepack',
-   subdir: 'scipy/integrate'
- )
- 
-+vode_module = custom_target('vode_module',
-+  output: ['_vode-f2pywrappers.f', '_vodemodule.c'],
-+  input: 'vode.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- py3.extension_module('_vode',
--  f2py_gen.process('vode.pyf'),
-+  vode_module,
-   link_with: [vode_lib],
-   c_args: [Wno_unused_variable],
-   link_args: version_link_args,
-@@ -139,8 +145,14 @@ py3.extension_module('_vode',
-   subdir: 'scipy/integrate'
- )
- 
-+lsoda_module = custom_target('lsoda_module',
-+  output: ['_lsoda-f2pywrappers.f', '_lsodamodule.c'],
-+  input: 'lsoda.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- py3.extension_module('_lsoda',
--  f2py_gen.process('lsoda.pyf'),
-+  lsoda_module,
-   link_with: [lsoda_lib, mach_lib],
-   c_args: [Wno_unused_variable],
-   dependencies: [lapack_dep, fortranobject_dep],
-@@ -150,8 +162,14 @@ py3.extension_module('_lsoda',
-   subdir: 'scipy/integrate'
- )
- 
-+_dop_module = custom_target('_dop_module',
-+  output: ['_dop-f2pywrappers.f', '_dopmodule.c'],
-+  input: 'dop.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- py3.extension_module('_dop',
--  f2py_gen.process('dop.pyf'),
-+  _dop_module,
-   link_with: [dop_lib],
-   c_args: [Wno_unused_variable],
-   dependencies: [lapack, fortranobject_dep],
-@@ -169,8 +187,14 @@ py3.extension_module('_test_multivariate',
-   install_tag: 'tests'
- )
- 
-+_test_odeint_banded_module = custom_target('_test_odeint_banded_module',
-+  output: ['_test_odeint_bandedmodule.c', '_test_odeint_banded-f2pywrappers.f'],
-+  input: 'tests/test_odeint_banded.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- py3.extension_module('_test_odeint_banded',
--  ['tests/banded5x5.f', f2py_gen.process('tests/test_odeint_banded.pyf')],
-+  ['tests/banded5x5.f', _test_odeint_banded_module],
-   link_with: [lsoda_lib, mach_lib],
-   fortran_args: _fflag_Wno_unused_dummy_argument,
-   link_args: version_link_args,
-diff --git a/scipy/interpolate/meson.build b/scipy/interpolate/meson.build
-index 69ec25f6af..38dd2a8cc3 100644
---- a/scipy/interpolate/meson.build
-+++ b/scipy/interpolate/meson.build
-@@ -143,9 +143,15 @@ py3.extension_module('_fitpack',
-   subdir: 'scipy/interpolate'
- )
- 
-+dfitpack_module = custom_target('dfitpack_module',
-+  output: ['_dfitpack-f2pywrappers.f', '_dfitpackmodule.c'],
-+  input: 'src/dfitpack.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- # TODO: Add flags for 64 bit ints
- py3.extension_module('_dfitpack',
--  f2py_gen.process('src/dfitpack.pyf'),
-+  dfitpack_module,
-   c_args: [Wno_unused_variable],
-   link_args: version_link_args,
-   dependencies: [lapack_dep, fortranobject_dep],
-diff --git a/scipy/io/meson.build b/scipy/io/meson.build
-index 60f71c6968..89a9cf69ba 100644
---- a/scipy/io/meson.build
-+++ b/scipy/io/meson.build
-@@ -1,6 +1,12 @@
-+_test_fortran_module = custom_target('_test_fortran_module',
-+  output: ['_test_fortranmodule.c'],
-+  input: 'test_fortran.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- py3.extension_module('_test_fortran',
-   [
--    f2py_gen.process('test_fortran.pyf'),
-+    _test_fortran_module,
-     '_test_fortran.f'
-   ],
-   c_args: [Wno_unused_variable],
-diff --git a/scipy/meson.build b/scipy/meson.build
-index a0857848a2..ff47bde52e 100644
---- a/scipy/meson.build
-+++ b/scipy/meson.build
-@@ -144,30 +144,6 @@ fortranobject_dep = declare_dependency(
-   compile_args: _f2py_c_args,
- )
- 
--f2py = find_program('f2py')
--# It should be quite rare for the `f2py` executable to not be the one from
--# `numpy` installed in the Python env we are building for (unless we are
--# cross-compiling). If it is from a different env, that is still fine as long
--# as it's not too old. We are only using f2py as a code generator, and the
--# output is not dependent on platform or Python version (see gh-20612 for more
--# details).
--# This should be robust enough. If not, we can make this more complex, using
--# a fallback to `python -m f2py` rather than erroring out.
--f2py_version = run_command([f2py, '-v'], check: true).stdout().strip()
--if f2py_version.version_compare('<'+min_numpy_version)
--  error(f'Found f2py executable is too old: @f2py_version@')
--endif
--
--# Note: this generato cannot handle:
--# 1. `.pyf.src` files, because `@BASENAME@` will still include .pyf
--# 2. targets with #include's (due to no `depend_files` - see feature request
--#    at meson#8295)
--f2py_gen = generator(generate_f2pymod,
--  arguments : ['@INPUT@', '-o', '@BUILD_DIR@'],
--  output : ['_@BASENAME@module.c', '_@BASENAME@-f2pywrappers.f'],
--)
--
--
- # TODO: 64-bit BLAS and LAPACK
- #
- # Note that this works as long as BLAS and LAPACK are detected properly via
-diff --git a/scipy/optimize/meson.build b/scipy/optimize/meson.build
-index 50d62ef68b..6cef85027a 100644
---- a/scipy/optimize/meson.build
-+++ b/scipy/optimize/meson.build
-@@ -92,12 +92,18 @@ py3.extension_module('_zeros',
-   subdir: 'scipy/optimize'
- )
- 
-+lbfgsb_module = custom_target('lbfgsb_module',
-+  output: ['_lbfgsb-f2pywrappers.f', '_lbfgsbmodule.c'],
-+  input: 'lbfgsb_src/lbfgsb.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- py3.extension_module('_lbfgsb',
-   [
-     'lbfgsb_src/lbfgsb.f',
-     'lbfgsb_src/linpack.f',
-     'lbfgsb_src/timer.f',
--    f2py_gen.process('lbfgsb_src/lbfgsb.pyf'),
-+    lbfgsb_module,
-   ],
-   fortran_args: fortran_ignore_warnings,
-   link_args: version_link_args,
-@@ -120,6 +126,12 @@ py3.extension_module('_moduleTNC',
-   subdir: 'scipy/optimize'
- )
- 
-+cobyla_module = custom_target('cobyla_module',
-+  output: ['_cobylamodule.c'],
-+  input: 'cobyla/cobyla.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- py3.extension_module('_cobyla',
--  [f2py_gen.process('cobyla/cobyla.pyf'), 'cobyla/cobyla2.f', 'cobyla/trstlp.f'],
-+  [cobyla_module, 'cobyla/cobyla2.f', 'cobyla/trstlp.f'],
-   c_args: [Wno_unused_variable],
-@@ -131,8 +143,14 @@ py3.extension_module('_cobyla',
-   subdir: 'scipy/optimize'
- )
- 
-+minpack2_module = custom_target('minpack2_module',
-+  output: ['_minpack2module.c'],
-+  input: 'minpack2/minpack2.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- py3.extension_module('_minpack2',
--  [f2py_gen.process('minpack2/minpack2.pyf'), 'minpack2/dcsrch.f', 'minpack2/dcstep.f'],
-+  [minpack2_module, 'minpack2/dcsrch.f', 'minpack2/dcstep.f'],
-   fortran_args: fortran_ignore_warnings,
-   link_args: version_link_args,
-   dependencies: [lapack, fortranobject_dep],
-@@ -142,8 +160,14 @@ py3.extension_module('_minpack2',
-   subdir: 'scipy/optimize'
- )
- 
-+slsqp_module = custom_target('slsqp_module',
-+  output: ['_slsqpmodule.c'],
-+  input: 'slsqp/slsqp.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- py3.extension_module('_slsqp',
--  [f2py_gen.process('slsqp/slsqp.pyf'), 'slsqp/slsqp_optmz.f'],
-+  [slsqp_module, 'slsqp/slsqp_optmz.f'],
-   fortran_args: fortran_ignore_warnings,
-   link_args: version_link_args,
-   dependencies: [fortranobject_dep],
-diff --git a/scipy/sparse/linalg/_propack/meson.build b/scipy/sparse/linalg/_propack/meson.build
-index 6714724958..df358df651 100644
---- a/scipy/sparse/linalg/_propack/meson.build
-+++ b/scipy/sparse/linalg/_propack/meson.build
-@@ -97,8 +97,14 @@ foreach ele: elements
-     gnu_symbol_visibility: 'hidden',
-   )
- 
-+  propack_module = custom_target('propack_module' + ele[0],
-+    output: [ele[0] + '-f2pywrappers.f', ele[0] + 'module.c'],
-+    input: ele[2],
-+    command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+  )
-+
-   propacklib = py3.extension_module(ele[0],
--    f2py_gen.process(ele[2]),
-+    propack_module,
-     link_with: propack_lib,
-     c_args: ['-U_OPENMP', _cpp_Wno_cpp],
-     fortran_args: _fflag_Wno_maybe_uninitialized,
-diff --git a/scipy/stats/meson.build b/scipy/stats/meson.build
-index 358279a93b..7c973b1cf3 100644
---- a/scipy/stats/meson.build
-+++ b/scipy/stats/meson.build
-@@ -31,8 +31,14 @@ py3.extension_module('_ansari_swilk_statistics',
-   subdir: 'scipy/stats'
- )
- 
-+mvn_module = custom_target('mvn_module',
-+  output: ['_mvn-f2pywrappers.f', '_mvnmodule.c'],
-+  input: 'mvn.pyf',
-+  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
-+)
-+
- py3.extension_module('_mvn',
--  [f2py_gen.process('mvn.pyf'), 'mvndst.f'],
-+  [mvn_module, 'mvndst.f'],
-   # Wno-surprising is to suppress a pointless warning with GCC 10-12
-   # (see GCC bug 98411: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98411)
-   fortran_args: [fortran_ignore_warnings, _fflag_Wno_surprising],
-diff --git a/tools/generate_f2pymod.py b/tools/generate_f2pymod.py
-index b6bc02eb04..3da75c14d1 100644
---- a/tools/generate_f2pymod.py
-+++ b/tools/generate_f2pymod.py
-@@ -9,6 +9,7 @@ import argparse
- import os
- import re
- import subprocess
-+import sys
- 
- 
- # START OF CODE VENDORED FROM `numpy.distutils.from_template`
-@@ -283,7 +284,7 @@ def main():
- 
-     # Now invoke f2py to generate the C API module file
-     if args.infile.endswith(('.pyf.src', '.pyf')):
--        p = subprocess.Popen(['f2py', fname_pyf,
-+        p = subprocess.Popen([sys.executable, '-m', 'numpy.f2py', fname_pyf,
-                             '--build-dir', outdir_abs], #'--quiet'],
-                             stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-                             cwd=os.getcwd())
--- 
-2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch b/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
deleted file mode 100644
index 9f45ad86..00000000
--- a/integration_tests/recipes/scipy/patches/0016-Make-sf_error_state_lib-a-static-library.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 9d93ca19f4ad0ca327964b6234316547d774b17f Mon Sep 17 00:00:00 2001
-From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
-Date: Sat, 17 Aug 2024 01:12:28 +0530
-Subject: [PATCH 16/18] Make `sf_error_state_lib` a static library
-
-wasm.ld does not support linkage with shared libraries. This patch
-changes `sf_error_state_lib` to a static one.
-
----
- scipy/special/meson.build | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/scipy/special/meson.build b/scipy/special/meson.build
-index 82b813ea85..24bee0a21c 100644
---- a/scipy/special/meson.build
-+++ b/scipy/special/meson.build
-@@ -33,7 +33,7 @@ else
-   scipy_import_dll_args = []
- endif
- 
--sf_error_state_lib = shared_library('sf_error_state',
-+sf_error_state_lib = static_library('sf_error_state',
-   ['sf_error_state.c'],
-   include_directories: ['../_lib', '../_build_utils/src'],
-   c_args: scipy_export_dll_args,
--- 
-2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch b/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
deleted file mode 100644
index 56be63ec..00000000
--- a/integration_tests/recipes/scipy/patches/0017-Remove-test-modules-that-fail-to-build.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-From e21f33695da3275ec81b5f94685f0e4ac92c9ad5 Mon Sep 17 00:00:00 2001
-From: Gyeongjae Choi 
-Date: Mon, 30 Oct 2023 14:35:04 +0000
-Subject: [PATCH 17/18] Remove test modules that fail to build
-
-These are tests and they have both void vs int return value problems and implicit
-function argument cast problems. Not worth fixing for tests.
-
----
- scipy/integrate/meson.build | 18 ------------------
- scipy/io/meson.build        | 21 ---------------------
- 2 files changed, 39 deletions(-)
-
-diff --git a/scipy/integrate/meson.build b/scipy/integrate/meson.build
-index ae9e2466e1..e11626db0d 100644
---- a/scipy/integrate/meson.build
-+++ b/scipy/integrate/meson.build
-@@ -187,24 +187,6 @@ py3.extension_module('_test_multivariate',
-   install_tag: 'tests'
- )
- 
--_test_odeint_banded_module = custom_target('_test_odeint_banded_module',
--  output: ['_test_odeint_bandedmodule.c', '_test_odeint_banded-f2pywrappers.f'],
--  input: 'tests/test_odeint_banded.pyf',
--  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
--)
--
--py3.extension_module('_test_odeint_banded',
--  ['tests/banded5x5.f', _test_odeint_banded_module],
--  link_with: [lsoda_lib, mach_lib],
--  fortran_args: _fflag_Wno_unused_dummy_argument,
--  link_args: version_link_args,
--  dependencies: [lapack_dep, fortranobject_dep],
--  install: true,
--  link_language: 'fortran',
--  subdir: 'scipy/integrate',
--  install_tag: 'tests'
--)
--
- subdir('_ivp')
- subdir('tests')
- 
-diff --git a/scipy/io/meson.build b/scipy/io/meson.build
-index d6fc6dc749..af04022208 100644
---- a/scipy/io/meson.build
-+++ b/scipy/io/meson.build
-@@ -1,24 +1,3 @@
--_test_fortran_module = custom_target('_test_fortran_module',
--  output: ['_test_fortranmodule.c'],
--  input: 'test_fortran.pyf',
--  command: [generate_f2pymod, '@INPUT@', '-o', '@OUTDIR@']
--)
--
--py3.extension_module('_test_fortran',
--  [
--    _test_fortran_module,
--    '_test_fortran.f'
--  ],
--  c_args: [Wno_unused_variable],
--  fortran_args: fortran_ignore_warnings,
--  link_args: version_link_args,
--  dependencies: [lapack_dep, fortranobject_dep],
--  install: true,
--  link_language: 'fortran',
--  subdir: 'scipy/io',
--  install_tag: 'tests'
--)
--
- py3.install_sources([
-     '__init__.py',
-     '_fortran.py',
--- 
-2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch b/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
deleted file mode 100644
index e2ffa67b..00000000
--- a/integration_tests/recipes/scipy/patches/0018-Fix-lapack-larfg-function-signature.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 8b06e7fef50327f84140cb09a3d9237e18b38a35 Mon Sep 17 00:00:00 2001
-From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
-Date: Thu, 5 Sep 2024 21:14:20 +0530
-Subject: [PATCH 18/18] Fix lapack larfg function signature
-
-This patch fixes the signature of the LAPACK routine larfg. Please
-see https://github.com/pyodide/pyodide/issues/3379 for more details.
-
-Co-authored-by: Ilhan Polat 
-Suggested-by: Hood Chatham 
-
----
- scipy/linalg/flapack_other.pyf.src | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/scipy/linalg/flapack_other.pyf.src b/scipy/linalg/flapack_other.pyf.src
-index 99d4886558..bf7256e605 100644
---- a/scipy/linalg/flapack_other.pyf.src
-+++ b/scipy/linalg/flapack_other.pyf.src
-@@ -2310,13 +2310,12 @@ function lange(norm,m,n,a,lda,work) result(n2)
-      dimension(m+1),intent(cache,hide) :: work
- end function lange
- 
--subroutine larfg(n, alpha, x, incx, tau, lx)
-+subroutine larfg(n, alpha, x, incx, tau)
-     integer intent(in), check(n>=1) :: n
-      intent(in,out) :: alpha
--     intent(in,copy,out), dimension(lx) :: x
-+     intent(in,copy,out), dimension(*), depend(n,incx), check(len(x) >= (n-2)*incx) :: x
-     integer intent(in), check(incx>0||incx<0) :: incx = 1
-      intent(out) :: tau
--    integer intent(hide),depend(x,n,incx),check(lx > (n-2)*incx) :: lx = len(x)
- end subroutine larfg
- 
- subroutine larf(side,m,n,v,incv,tau,c,ldc,work,lwork)
--- 
-2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/scipy-conftest.py b/integration_tests/recipes/scipy/scipy-conftest.py
index e7adcc8b..093340b6 100644
--- a/integration_tests/recipes/scipy/scipy-conftest.py
+++ b/integration_tests/recipes/scipy/scipy-conftest.py
@@ -1,4 +1,6 @@
+import random
 import re
+import threading
 
 import pytest
 
@@ -15,9 +17,13 @@
 todo_memory_corruption_msgt = "TODO memory corruption"
 todo_genuine_difference_msg = "TODO genuine difference to be investigated"
 todo_fp_exception_msg = "TODO did not raise maybe no floating point exception support?"
+todo_overflow_msg = "TODO overflow not raised"
+todo_runtime_warning = "TODO runtime warning not shown"
 
 
 tests_to_mark = [
+    ("test_odeint_jac\\.py", skip, "test module removed: uses Fortran extension not built for WASM"),
+    ("io/tests/test_fortran\\.py", skip, "test module removed: uses Fortran extension not built for WASM"),
     # scipy/_lib/tests
     (
         "test__threadsafety.py::test_parallel_threads",
@@ -27,6 +33,7 @@
     ("test__threadsafety.py::test_parallel_threads", xfail, thread_msg),
     ("test__util.py::test_pool", xfail, process_msg),
     ("test__util.py::test_mapwrapper_parallel", xfail, process_msg),
+    ("test__util.py::test__workers_wrapper", xfail, process_msg),
     ("test_ccallback.py::test_threadsafety", xfail, thread_msg),
     ("test_import_cycles.py::test_modules_importable", xfail, process_msg),
     ("test_import_cycles.py::test_public_modules_importable", xfail, process_msg),
@@ -48,7 +55,7 @@
         thread_msg,
     ),
     # scipy/integrate tests
-    ("test__quad_vec.py::test_quad_vec_pool", xfail, process_msg),
+    ("test__quad_vec.py::TestQuadVec.test_quad_vec_pool.*", xfail, process_msg),
     (
         "test_quadpack.py.+TestCtypesQuad.test_ctypes.*",
         xfail,
@@ -70,6 +77,11 @@
         xfail,
         "TODO error not raised, maybe due to no floating point exception?",
     ),
+    (
+        "test_rbf.py::test_rbf_concurrency",
+        xfail,
+        thread_msg,
+    ),
     # scipy/io
     (
         "test_mmio.py::.+fast_matrix_market",
@@ -120,9 +132,44 @@
         "TODO no warnings emitted maybe due to no floating point exception?",
     ),
     ("test_minpack.py::TestFSolve.test_concurrent.+", xfail, process_msg),
-    ("test_minpack.py::TestLeastSq.test_concurrent+", xfail, process_msg),
+    ("test_minpack.py::TestLeastSq.test_concurrent.+", xfail, process_msg),
     ("test_optimize.py::test_cobyla_threadsafe", xfail, thread_msg),
     ("test_optimize.py::TestBrute.test_workers", xfail, process_msg),
+    (
+        "test__numdiff.py::TestApproxDerivativesDense.test_scalar_vector",
+        xfail,
+        process_msg,
+    ),
+    (
+        "test__numdiff.py::TestApproxDerivativesDense.test_workers_evaluations_and_nfev",
+        xfail,
+        process_msg,
+    ),
+    (
+        "test__numdiff.py::TestApproxDerivativesDense.test_vector_vector",
+        xfail,
+        process_msg,
+    ),
+    (
+        "test__numdiff.py::TestApproxDerivativeSparse.test_all",
+        xfail,
+        process_msg,
+    ),
+    (
+        ".*test_workers.*",
+        xfail,
+        process_msg,
+    ),
+    (
+        "test_optimize.py::TestWorkers.*",
+        xfail,
+        process_msg,
+    ),
+    (
+        "test_optimize.py::test_multiprocessing_too_many_open_files_23080",
+        xfail,
+        process_msg,
+    ),
     # scipy/signal/tests
     (
         "test_signaltools.py::TestMedFilt.test_medfilt2d_parallel",
@@ -189,6 +236,11 @@
         xfail,
         todo_fp_exception_msg,
     ),
+    (
+        "test_sf_error.py::test_check_overflow_message",
+        xfail,
+        todo_overflow_msg,
+    ),
     (
         "test_kdeoth.py::test_kde_[12]d",
         xfail,
@@ -236,7 +288,7 @@
     ),
     ("test_qmc.py::TestVDC.test_van_der_corput", xfail, thread_msg),
     ("test_qmc.py::TestHalton.test_workers", xfail, thread_msg),
-    ("test_qmc.py::TestUtils.test_discrepancy_parallel", xfail, thread_msg),
+    ("test_qmc.py::TestUtils.test_discrepancy_parallel", skip, "thread constructor fails and leaves C destructor with WASM function-pointer mismatch, causing a fatal error during pytest GC cleanup"),
     (
         "test_qmc.py::TestMultivariateNormalQMC.test_validations",
         xfail,
@@ -269,9 +321,50 @@
         xfail,
         fp_exception_msg,
     ),
+    (
+        "test_fit.py::test_fit_error",
+        xfail,
+        todo_runtime_warning,
+    ),
+    (
+        "test_stats.py::TestWassersteinDistance.test_inf_values",
+        xfail,
+        todo_runtime_warning,
+    ),
+    (
+        "test_stats.py::TestEnergyDistance.test_inf_values",
+        xfail,
+        todo_runtime_warning,
+    ),
+    # many
+    (".*test_concurrency.*", xfail, thread_msg),
 ]
 
 
+def pytest_configure(config):
+    # threading.get_native_id is not available in Pyodide's WASM environment
+    if not hasattr(threading, "get_native_id"):
+        threading.get_native_id = lambda: random.randint(0, 10000)
+
+
+@pytest.hookimpl(trylast=True)
+def pytest_sessionfinish(session, exitstatus):  # noqa: ARG001
+    # C-extension destructors in SciPy call Fortran functions with void/int
+    # signature mismatches. These run both
+    # during the gc cleanup (gc_collect_harder in _pytest/unraisableexception)
+    # and during Python's own finalization sequence, causing fatal errors that
+    # cannot be caught in Python as they crash the interpreter. os._exit can
+    # at least bypass both of these.
+    import os
+    import sys
+
+    # For outputs (can't get this to work)
+    # sys.stdout.flush()
+    # sys.stderr.flush()
+    # test summary line doesn't work so we can't see how many passed/skipped/etc...
+    os._exit(int(exitstatus))
+
+
 def pytest_collection_modifyitems(config, items):
     for item in items:
         path, line, name = item.reportinfo()
diff --git a/integration_tests/recipes/scipy/scipy-pytest.js b/integration_tests/recipes/scipy/scipy-pytest.js
deleted file mode 100644
index 6c3e54e5..00000000
--- a/integration_tests/recipes/scipy/scipy-pytest.js
+++ /dev/null
@@ -1,84 +0,0 @@
-const { opendir } = require("node:fs/promises");
-const { loadPyodide } = require("pyodide");
-
-async function main() {
-  let exit_code = 0;
-  try {
-    global.pyodide = await loadPyodide();
-    let pyodide = global.pyodide;
-    const FS = pyodide.FS;
-    const NODEFS = FS.filesystems.NODEFS;
-
-    let mountDir = "/mnt";
-    pyodide.FS.mkdir(mountDir);
-    pyodide.FS.mount(pyodide.FS.filesystems.NODEFS, { root: "." }, mountDir);
-
-    // Copy pytest-specific files dir if they exist
-    await pyodide.runPythonAsync(`
-       import shutil
-       import os
-
-       pytest_filenames = ["/mnt/conftest.py", "/mnt/pytest.ini"]
-
-       for filename in pytest_filenames:
-           if os.path.exists(filename):
-               shutil.copy(filename, ".")
-
-       conftest_filename = "/mnt/conftest.py"
-       if os.path.exists(conftest_filename):
-           shutil.copy(conftest_filename, ".")
-    `);
-
-    await pyodide.loadPackage(["micropip"]);
-    await pyodide.runPythonAsync(`
-       import micropip
-
-       await micropip.install('scipy')
-
-       try:
-           await micropip.install('scipy-tests')
-       except ValueError:
-           print('Hoping scipy tests are included in the scipy wheel')
-
-       pkg_list = micropip.list()
-       print(pkg_list)
-    `);
-
-    // XXX: some Fortran test modules are removed in Pyodide through a patch
-    // https://github.com/pyodide/pyodide/blob/main/packages/scipy/patches/0008-Remove-test-modules-that-fails-to-build.patch
-    // In order to avoid import errors during test discovery, we delete the
-    // problematic files. There seems to be no simpler way to do this with
-    // pytest, in particular --ignore-glob still imports the ignored file for
-    // some reason.
-    await pyodide.runPythonAsync(`
-      from pathlib import Path
-
-      import scipy.io.tests
-      path = Path(scipy.io.tests.__file__).parent / "test_fortran.py"
-      os.unlink(path)
-
-      import scipy.integrate.tests
-      path = Path(scipy.integrate.tests.__file__).parent / "test_odeint_jac.py"
-      os.unlink(path)
-    `);
-
-    await pyodide.runPythonAsync(
-      "import micropip; micropip.install(['pytest', 'hypothesis', 'pooch', 'lzma'])",
-    );
-    let pytest = pyodide.pyimport("pytest");
-    let args = process.argv.slice(2);
-    console.log("pytest args:", args);
-    exit_code = pytest.main(pyodide.toPy(args));
-  } catch (e) {
-    console.error(e);
-    // Arbitrary exit code here. I have seen this code reached instead of a
-    // Pyodide fatal error sometimes (I guess kind of similar to a random
-    // Python error). When there is a Pyodide fatal error we don't end up here
-    // somehow, and the exit code is 7
-    exit_code = 66;
-  } finally {
-    process.exit(exit_code);
-  }
-}
-
-main();
diff --git a/integration_tests/recipes/scipy/test_scipy.py b/integration_tests/recipes/scipy/test_scipy.py
index ebd09bed..fc018ab5 100644
--- a/integration_tests/recipes/scipy/test_scipy.py
+++ b/integration_tests/recipes/scipy/test_scipy.py
@@ -1,6 +1,8 @@
 import pytest
 from pytest_pyodide import run_in_pyodide
 
+from conftest import package_is_built
+
 
 @pytest.mark.driver_timeout(40)
 @run_in_pyodide(packages=["scipy"])
@@ -43,9 +45,15 @@ def test_binom_ppf(selenium):
     assert binom.ppf(0.9, 1000, 0.1) == 112
 
 
+_scipy_test_packages = ["pytest", "scipy", "micropip"] + (
+    ["scipy-tests"] if package_is_built("scipy-tests") else []
+)
+
+
+@pytest.mark.xfail_browsers(node="Can't fetch metadata for 'hypothesis'")
 @pytest.mark.skip_pyproxy_check
 @pytest.mark.driver_timeout(40)
-@run_in_pyodide(packages=["pytest", "scipy-tests", "micropip"])
+@run_in_pyodide(packages=_scipy_test_packages)
 async def test_scipy_pytest(selenium):
     import pytest
 
@@ -139,9 +147,9 @@ def test_dblquad(selenium):
     unit_square_area = scipy.integrate.dblquad(
         lambda y, x: 1, 0, 1, lambda x: 0, lambda x: 1
     )
-    assert (
-        abs(unit_square_area[0] - 1) < unit_square_area[1]
-    ), f"Unit square area calculated using scipy.integrate.dblquad of {unit_square_area[0]} (+- {unit_square_area[0]}) is too far from 1.0"
+    assert abs(unit_square_area[0] - 1) < unit_square_area[1], (
+        f"Unit square area calculated using scipy.integrate.dblquad of {unit_square_area[0]} (+- {unit_square_area[0]}) is too far from 1.0"
+    )
 
 
 import shutil

From f98ef4381f52d4d1542a3da103a6ae249ec204e6 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 15:06:05 +0530
Subject: [PATCH 19/71] Rename `openblas` to `libopenblas`

---
 integration_tests/recipes/{openblas => libopenblas}/meta.yaml     | 0
 .../patches/0001-Add-Wno-return-type-flag.patch                   | 0
 ...0002-Align-xerbla_array-signature-with-scipy-expectation.patch | 0
 3 files changed, 0 insertions(+), 0 deletions(-)
 rename integration_tests/recipes/{openblas => libopenblas}/meta.yaml (100%)
 rename integration_tests/recipes/{openblas => libopenblas}/patches/0001-Add-Wno-return-type-flag.patch (100%)
 rename integration_tests/recipes/{openblas => libopenblas}/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch (100%)

diff --git a/integration_tests/recipes/openblas/meta.yaml b/integration_tests/recipes/libopenblas/meta.yaml
similarity index 100%
rename from integration_tests/recipes/openblas/meta.yaml
rename to integration_tests/recipes/libopenblas/meta.yaml
diff --git a/integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch b/integration_tests/recipes/libopenblas/patches/0001-Add-Wno-return-type-flag.patch
similarity index 100%
rename from integration_tests/recipes/openblas/patches/0001-Add-Wno-return-type-flag.patch
rename to integration_tests/recipes/libopenblas/patches/0001-Add-Wno-return-type-flag.patch
diff --git a/integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch b/integration_tests/recipes/libopenblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
similarity index 100%
rename from integration_tests/recipes/openblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
rename to integration_tests/recipes/libopenblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch

From 2c7e98fded921558f3319996c9214c6b793075f9 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 15:08:41 +0530
Subject: [PATCH 20/71] Change openblas to libopenblas in recipe file

---
 integration_tests/recipes/libopenblas/meta.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/integration_tests/recipes/libopenblas/meta.yaml b/integration_tests/recipes/libopenblas/meta.yaml
index 1325649a..3ea27603 100644
--- a/integration_tests/recipes/libopenblas/meta.yaml
+++ b/integration_tests/recipes/libopenblas/meta.yaml
@@ -1,5 +1,5 @@
 package:
-  name: openblas
+  name: libopenblas
   version: 0.3.26
   tag:
     - library

From aac25bd2fc245d30301b11d8904d2797d6a168ce Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 15:19:16 +0530
Subject: [PATCH 21/71] Add Boost recipe needed for SciPy

---
 integration_tests/recipes/libboost/meta.yaml | 37 ++++++++++++++++++++
 1 file changed, 37 insertions(+)
 create mode 100644 integration_tests/recipes/libboost/meta.yaml

diff --git a/integration_tests/recipes/libboost/meta.yaml b/integration_tests/recipes/libboost/meta.yaml
new file mode 100644
index 00000000..671e5047
--- /dev/null
+++ b/integration_tests/recipes/libboost/meta.yaml
@@ -0,0 +1,37 @@
+package:
+  name: libboost
+  version: 1.84.0
+  tag:
+    - library
+    - static_library
+source:
+  url: https://github.com/boostorg/boost/releases/download/boost-1.84.0/boost-1.84.0.tar.gz
+  sha256: 4d27e9efed0f6f152dc28db6430b9d3dfb40c0345da7342eaa5a987dde57bd95
+
+build:
+  type: static_library
+  script: |
+    export INSTALL_DIR=${WASM_LIBRARY_DIR}
+    ./bootstrap.sh --prefix=${INSTALL_DIR}
+
+    # https://github.com/emscripten-core/emscripten/issues/17052
+    # Without this, boost outputs WASM modules not static library archives as an output.
+    # I don't understand why... the jam file used by boost is quite hard to understand.
+    printf "using clang : emscripten : emcc : emar emranlib emlink ;" | tee -a ./project-config.jam
+
+    ./b2 variant=release toolset=clang-emscripten link=static threading=single \
+      --with-date_time --with-filesystem \
+      --with-system --with-regex --with-chrono --with-random --with-program_options --disable-icu \
+      cxxflags="$SIDE_MODULE_CXXFLAGS -fwasm-exceptions -DBOOST_SP_DISABLE_THREADS=1" \
+      cflags="$SIDE_MODULE_CFLAGS -fwasm-exceptions -DBOOST_SP_DISABLE_THREADS=1" \
+      linkflags="-fpic $SIDE_MODULE_LDFLAGS" \
+      --layout=system -j"${PYODIDE_JOBS:-3}" --prefix=${INSTALL_DIR} \
+      install
+
+about:
+  home: https://www.boost.org/
+  summary: Free peer-reviewed portable C++ source libraries.
+  license: Boost
+extra:
+  recipe-maintainers:
+    - johnwason

From 2e9ed3f582e59a83f8a9f7947d9bbe76578c09fe Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 15:21:40 +0530
Subject: [PATCH 22/71] Update OpenBLAS version and patches

---
 .../recipes/libopenblas/meta.yaml             | 32 ++++++--
 .../0001-Add-Wno-return-type-flag.patch       |  9 +--
 ...ray-signature-with-scipy-expectation.patch |  4 +-
 .../patches/0003-Skip-linktest.patch          | 75 +++++++++++++++++++
 4 files changed, 107 insertions(+), 13 deletions(-)
 create mode 100644 integration_tests/recipes/libopenblas/patches/0003-Skip-linktest.patch

diff --git a/integration_tests/recipes/libopenblas/meta.yaml b/integration_tests/recipes/libopenblas/meta.yaml
index 3ea27603..0fb20390 100644
--- a/integration_tests/recipes/libopenblas/meta.yaml
+++ b/integration_tests/recipes/libopenblas/meta.yaml
@@ -1,14 +1,17 @@
 package:
   name: libopenblas
-  version: 0.3.26
+  version: 0.3.28
   tag:
+    - core
     - library
+    - shared_library
 source:
-  sha256: 4e6e4f5cb14c209262e33e6816d70221a2fe49eb69eaf0a06f065598ac602c68
-  url: https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.26/OpenBLAS-0.3.26.tar.gz
+  sha256: f1003466ad074e9b0c8d421a204121100b0751c96fc6fcf3d1456bd12f8a00a1
+  url: https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.28/OpenBLAS-0.3.28.tar.gz
   patches:
     - patches/0001-Add-Wno-return-type-flag.patch
     - patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
+    - patches/0003-Skip-linktest.patch
 
 build:
   type: shared_library
@@ -29,15 +32,32 @@ build:
     sed -ri 's@int ([cz](dotc|dotu|ladiv))@void \1@g' lapack-netlib/SRC/*.c\
         lapack-netlib/SRC/DEPRECATED/*.c
 
-    emmake make libs shared CC=emcc HOSTCC=gcc TARGET=RISCV64_GENERIC NOFORTRAN=1 NO_LAPACKE=1 \
-        USE_THREAD=0 LDFLAGS="${SIDE_MODULE_LDFLAGS}"
+    # When TARGET=RISCV64_GENERIC, OpenBLAS adds `-march` and `-mabi` flags to the compiler.
+    # However, they are not supported by Emscripten, and started to cause build failures from recent Emscripten versions (>4.X).
+    sed -i 's@ifeq ($(CORE), RISCV64_GENERIC)@ifeq ($(CORE), NOT_RISCV64_GENERIC)@g' Makefile.riscv64
+    sed -i 's@ifeq ($(TARGET), RISCV64_GENERIC)@ifeq ($(TARGET), NOT_RISCV64_GENERIC)@g' Makefile.prebuild
+
+    emmake make libs shared \
+        BINARY=32 \
+        CC="emcc -msimd128" \
+        HOSTCC=gcc \
+        TARGET=RISCV64_GENERIC \
+        NOFORTRAN=1 NO_LAPACKE=1 \
+        USE_THREAD=0 \
+        LDFLAGS="${SIDE_MODULE_LDFLAGS}"
     mkdir -p dist
+
     # Add libf2c symbols to libopenblas.so
-    emcc ${WASM_LIBRARY_DIR}/lib/libf2c.a libopenblas.a ${SIDE_MODULE_LDFLAGS} \
+    emcc ${WASM_LIBRARY_DIR}/lib/libf2c.a libopenblas.a \
+        ${SIDE_MODULE_LDFLAGS} \
+        -msimd128 \
         -o libopenblas.so
 
     cp libopenblas.so dist
     emmake make install PREFIX=${WASM_LIBRARY_DIR}
+    # We need to copy the shared library again as the make install
+    # does not know we've modified the binary with libf2c symbols.
+    cp dist/libopenblas.so ${WASM_LIBRARY_DIR}/lib/libopenblas.so
 
 requirements:
   host:
diff --git a/integration_tests/recipes/libopenblas/patches/0001-Add-Wno-return-type-flag.patch b/integration_tests/recipes/libopenblas/patches/0001-Add-Wno-return-type-flag.patch
index ae57a81a..8dcfc60a 100644
--- a/integration_tests/recipes/libopenblas/patches/0001-Add-Wno-return-type-flag.patch
+++ b/integration_tests/recipes/libopenblas/patches/0001-Add-Wno-return-type-flag.patch
@@ -1,21 +1,20 @@
-From 09fd1aa0aa6a98e1cebaa6e34fca1e424dab8f48 Mon Sep 17 00:00:00 2001
+From 3111f04db010f53a2634db4f4e8e35a2d9a2957b Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= 
 Date: Fri, 9 Dec 2022 16:40:13 +0100
-Subject: [PATCH 1/2] Add -Wno-return-type flag
+Subject: [PATCH 1/3] Add -Wno-return-type flag
 
 This is needed because we are changing many signatures to return int instead of
 void with some regex expressions but we are not modifying the returned value
  which would potentially be a lot more tricky.
-
 ---
  Makefile.rule | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/Makefile.rule b/Makefile.rule
-index 5f787a9c..6890046a 100644
+index daf2d958d..6595d4271 100644
 --- a/Makefile.rule
 +++ b/Makefile.rule
-@@ -228,7 +228,7 @@ NO_AFFINITY = 1
+@@ -231,7 +231,7 @@ NO_AFFINITY = 1
  # Common Optimization Flag;
  # The default -O2 is enough.
  # Flags for POWER8 are defined in Makefile.power. Don't modify COMMON_OPT
diff --git a/integration_tests/recipes/libopenblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch b/integration_tests/recipes/libopenblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
index d7ba240d..09a56911 100644
--- a/integration_tests/recipes/libopenblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
+++ b/integration_tests/recipes/libopenblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
@@ -1,7 +1,7 @@
-From fb8f9ec54121a889783cce3d42ea841cc513a22e Mon Sep 17 00:00:00 2001
+From 8ce75f14b82ed67eaf0eaceea0c8092851af00c2 Mon Sep 17 00:00:00 2001
 From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= 
 Date: Fri, 7 Apr 2023 10:27:59 +0200
-Subject: [PATCH 2/2] Align xerbla_array signature with scipy expectation
+Subject: [PATCH 2/3] Align xerbla_array signature with scipy expectation
 
 ---
  lapack-netlib/SRC/xerbla_array.c | 2 +-
diff --git a/integration_tests/recipes/libopenblas/patches/0003-Skip-linktest.patch b/integration_tests/recipes/libopenblas/patches/0003-Skip-linktest.patch
new file mode 100644
index 00000000..2f51aa2e
--- /dev/null
+++ b/integration_tests/recipes/libopenblas/patches/0003-Skip-linktest.patch
@@ -0,0 +1,75 @@
+From e66fa1d85166c1bd27a52d09221f5b5575ba63ca Mon Sep 17 00:00:00 2001
+From: Hood Chatham 
+Date: Wed, 22 Jan 2025 13:52:55 +0100
+Subject: [PATCH 3/3] Skip linktest
+
+---
+ exports/Makefile | 17 ++++++++---------
+ 1 file changed, 8 insertions(+), 9 deletions(-)
+
+diff --git a/exports/Makefile b/exports/Makefile
+index 7682f851d..86b2cd2f4 100644
+--- a/exports/Makefile
++++ b/exports/Makefile
+@@ -184,24 +184,24 @@ ifeq ($(F_COMPILER), INTEL)
+ 	$(FC) $(FFLAGS) $(LDFLAGS) -shared -o ../$(LIBSONAME) \
+ 	-Wl,--whole-archive $< -Wl,--no-whole-archive \
+ 	-Wl,-soname,$(INTERNALNAME) $(EXTRALIB)
+-	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
++	echo OK.
+ else ifeq ($(F_COMPILER), FLANG)
+ 	$(FC) $(FFLAGS) $(LDFLAGS) -shared -o ../$(LIBSONAME) \
+ 	-Wl,--whole-archive $< -Wl,--no-whole-archive \
+ 	-Wl,-soname,$(INTERNALNAME) $(EXTRALIB)
+-	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
++	echo OK.
+ else
+ ifneq ($(C_COMPILER), LSB)
+ 	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o ../$(LIBSONAME) \
+ 	-Wl,--whole-archive $< -Wl,--no-whole-archive \
+ 	-Wl,-soname,$(INTERNALNAME) $(EXTRALIB)
+-	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
++	echo OK.
+ else
+ #for LSB
+ 	env LSBCC_SHAREDLIBS=gfortran $(CC) $(CFLAGS) $(LDFLAGS) -shared -o ../$(LIBSONAME) \
+ 	-Wl,--whole-archive $< -Wl,--no-whole-archive \
+ 	-Wl,-soname,$(INTERNALNAME) $(EXTRALIB)
+-	$(FC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
++	echo OK.
+ endif
+ endif
+ 	rm -f linktest
+@@ -223,7 +223,7 @@ endif
+ 	$(CC) $(CFLAGS) $(LDFLAGS)  -shared -o ../$(LIBSONAME) \
+ 	-Wl,--whole-archive $< -Wl,--no-whole-archive \
+ 	$(FEXTRALIB) $(EXTRALIB)
+-	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
++	echo OK.
+ 	rm -f linktest
+ 
+ endif
+@@ -241,7 +241,7 @@ ifeq ($(OSNAME), SunOS)
+ so : ../$(LIBSONAME)
+ 	$(CC) $(CFLAGS) $(LDFLAGS)  -shared -o ../$(LIBSONAME) \
+ 	-Wl,--whole-archive ../$(LIBNAME) -Wl,--no-whole-archive $(EXTRALIB)
+-	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
++	echo OK.
+ 	rm -f linktest
+ 
+ endif
+@@ -283,9 +283,8 @@ objcopy.def : $(GENSYM) ../Makefile.system ../getarch.c
+ objconv.def : $(GENSYM) ../Makefile.system ../getarch.c
+ 	./$(GENSYM) objconv $(ARCH) "$(BU)" $(EXPRECISION) $(NO_CBLAS)  $(NO_LAPACK) $(NO_LAPACKE) $(NEED2UNDERSCORES) $(ONLY_CBLAS) "$(SYMBOLPREFIX)" "$(SYMBOLSUFFIX)" $(BUILD_LAPACK_DEPRECATED) $(BUILD_BFLOAT16) $(BUILD_SINGLE) $(BUILD_DOUBLE) $(BUILD_COMPLEX) $(BUILD_COMPLEX16) > $(@F)
+ 
+-test : linktest.c
+-	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) -lm && echo OK.
+-	rm -f linktest
++test :
++	echo OK.
+ 
+ linktest.c : $(GENSYM) ../Makefile.system ../getarch.c
+ 	./$(GENSYM) linktest  $(ARCH) "$(BU)" $(EXPRECISION) $(NO_CBLAS) $(NO_LAPACK) $(NO_LAPACKE) $(NEED2UNDERSCORES) $(ONLY_CBLAS) "$(SYMBOLPREFIX)" "$(SYMBOLSUFFIX)" $(BUILD_LAPACK_DEPRECATED) $(BUILD_BFLOAT16) $(BUILD_SINGLE) $(BUILD_DOUBLE) $(BUILD_COMPLEX) $(BUILD_COMPLEX16) > linktest.c
+-- 
+2.34.1
+

From 24746e6882b8f243d6cf5a1d3c78511409169939 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 16:31:55 +0530
Subject: [PATCH 23/71] Update `_find_executable_and_scripts` as per build
 1.5.0

---
 pyodide_build/vendor/_pypabuild.py | 25 +++++++++++++++----------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/pyodide_build/vendor/_pypabuild.py b/pyodide_build/vendor/_pypabuild.py
index 79ca44d2..0788500c 100644
--- a/pyodide_build/vendor/_pypabuild.py
+++ b/pyodide_build/vendor/_pypabuild.py
@@ -135,16 +135,14 @@ def _handle_build_error() -> Iterator[None]:
         _error(str(e))
 
 
-def _get_venv_paths(path: str) -> dict[str, str]:
+# Vendored from pypa/build v1.5.0. See source at:
+# https://github.com/pypa/build/blob/615d04cfc52ac3c1592a463f0afe484fee1cc368/src/build/env.py#L461-L501
+def _find_executable_and_scripts(path: str) -> tuple[str, str, str]:
     """
-    Find the sysconfig paths for a virtual environment.
+    Detect the Python executable and script folder of a virtual environment.
 
-    Copied from pypabuild (https://github.com/pypa/build/blob/562907e605c3becb135ac52b6eb2aa939e84bdda/src/build/env.py#L326)
-
-    Parameters
-    ----------
-    path
-        The root path of the virtual environment
+    :param path: The location of the virtual environment
+    :return: The Python executable, script folder, and purelib folder
     """
     config_vars = (
         sysconfig.get_config_vars().copy()
@@ -158,7 +156,7 @@ def _get_venv_paths(path: str) -> dict[str, str]:
         # The distributors are encouraged to set a "venv" scheme to be used for this.
         # See https://bugs.python.org/issue45413
         # and https://github.com/pypa/virtualenv/issues/2208
-        paths = sysconfig.get_paths(scheme="venv", vars=config_vars)
+        paths = sysconfig.get_paths(scheme="venv", vars=config_vars)  # pragma: no cover
     elif "posix_local" in scheme_names:
         # The Python that ships on Debian/Ubuntu varies the default scheme to
         # install to /usr/local
@@ -176,4 +174,11 @@ def _get_venv_paths(path: str) -> dict[str, str]:
     else:
         paths = sysconfig.get_paths(vars=config_vars)
 
-    return paths
+    executable = os.path.join(
+        paths["scripts"], "python.exe" if os.name == "nt" else "python"
+    )
+    if not os.path.exists(executable):
+        msg = f"Virtual environment creation failed, executable {executable} missing"
+        raise RuntimeError(msg)
+
+    return executable, paths["scripts"], paths["purelib"]

From eedcb3163d06c7f34cb26cbbf2ee6bc9c708e7a1 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 16:36:56 +0530
Subject: [PATCH 24/71] Better docstring

---
 pyodide_build/build_env.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py
index ffb967dd..913e1d37 100644
--- a/pyodide_build/build_env.py
+++ b/pyodide_build/build_env.py
@@ -258,7 +258,7 @@ def get_unisolated_packages() -> dict[str, str]:
 
 def get_unisolated_files(package_name: str) -> tuple[Path, list[str]]:
     """
-    Get a list of unisolated files for a package.
+    Get an unisolated package's cross-build files.
 
     Parameters
     ----------
@@ -268,6 +268,7 @@ def get_unisolated_files(package_name: str) -> tuple[Path, list[str]]:
     Returns
     -------
     A tuple of the package directory and a list of file paths relative to the package directory.
+
     """
     PYODIDE_ROOT = get_pyodide_root()
 

From 491bb9ca1b3a680a143b56a02c381758ed0dbe09 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 16:43:58 +0530
Subject: [PATCH 25/71] Rework `AVOIDED_REQUIREMENTS` bits

---
 pyodide_build/pypabuild.py | 132 ++++++++++++++-----------------------
 1 file changed, 48 insertions(+), 84 deletions(-)

diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 5296322c..4c017654 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -26,20 +26,11 @@
 from pyodide_build.vendor._pypabuild import (
     _DefaultIsolatedEnv,
     _error,
-    _get_venv_paths,
+    _find_executable_and_scripts,
     _handle_build_error,
     _styles,
 )
 
-AVOIDED_REQUIREMENTS = [
-    # We don't want to install cmake Python package inside the isolated env as it will shadow
-    # the pywasmcross cmake wrapper.
-    # TODO: Find a way to make scikit-build use the pywasmcross cmake wrapper.
-    "cmake",
-    # mesonpy installs patchelf in linux platform but we don't want it.
-    "patchelf",
-]
-
 # corresponding env variables for symlinks
 SYMLINK_ENV_VARS = {
     "cc": "CC",
@@ -102,8 +93,6 @@ def _runner(cmd, cwd=None, extra_environ=None):
 def symlink_unisolated_packages(
     env: DefaultIsolatedEnv, reqs: set[str] | None = None
 ) -> None:
-    from pyodide_build.build_env import get_build_flag
-
     pyversion = get_pyversion()
     site_packages_path = f"lib/{pyversion}/site-packages"
     env_site_packages = Path(env.path) / site_packages_path
@@ -117,38 +106,8 @@ def symlink_unisolated_packages(
     shutil.copy(sysconfigdata_path, env_site_packages)
 
 
-def _remove_avoided_requirements(
-    requires: set[str],
-    avoided_requirements: set[str] | list[str],
-) -> set[str]:
-    """
-    Remove requirements that are in the list of avoided requirements.
-
-    Parameters
-    ----------
-    requires
-        The set of requirements to filter.
-    avoided_requirements
-        The set of requirements to avoid.
-
-    Returns
-    -------
-    The filtered set of requirements.
-    """
-    avoided_requirements = set(avoided_requirements)
-    for reqstr in list(requires):
-        req = Requirement(reqstr)
-        for avoid_name in avoided_requirements:
-            if avoid_name in req.name.lower():
-                requires.remove(reqstr)
-                break
-
-    return requires
-
-
 def _replace_unisolated_packages(
-    requires: set[str],
-    unisolated_packages: dict[str, str],
+    reqs: set[str], unisolated_packages: dict[str, str]
 ) -> tuple[set[str], set[str]]:
     """
     Replace unisolated packages with the correct version.
@@ -162,40 +121,23 @@ def _replace_unisolated_packages(
 
     Returns
     -------
-    tuple of (The filtered set of requirements, The set of unisolated requirements)
+    A tuple of (the filtered set of requirements, the set of unisolated requirements)
     """
-    requires_new = requires.copy()
-    unisolated = set()
-    for reqstr in list(requires):
-        req = Requirement(reqstr)
-        for name, version in unisolated_packages.items():
-            if req.name == name:
-                # TODO: find a better way to handle this case
-                if not req.specifier.contains(version):
-                    print(
-                        f"WARNING: found build dependency {req} but the only supported cross-build version is {name}=={version}"
-                    )
-                    print(f"WARNING: using {name}=={version} instead")
-
-                requires_new.remove(reqstr)
-                requires_new.add(f"{name}=={version}")
-                unisolated.add(name)
-                break
-        else:
-            # oldest-supported-numpy is a meta package for numpy
-            # TODO: use dependency resolution instead of hardcoding this
-            if req.name == "oldest-supported-numpy" and "numpy" in unisolated_packages:
-                requires_new.remove(reqstr)
-                requires_new.add(f"numpy=={unisolated_packages['numpy']}")
-                unisolated.add("numpy")
-                break
-
-    return requires_new, unisolated
-
-
-def _install_cross_build_files(path: str, unisolated: set[str]) -> None:
+    new_reqs = reqs.copy()
+    unisolated: set[str] = set()
+    for reqstr in list(reqs):
+        name = Requirement(reqstr).name
+        if name in unisolated_packages:
+            new_reqs.discard(reqstr)
+            new_reqs.add(f"{name}=={unisolated_packages[name]}")
+            unisolated.add(name)
+    return new_reqs, unisolated
+
+
+def _install_cross_build_files(venv_path: str, unisolated: set[str]) -> None:
     """
-    Install the cross build files to the isolated environment.
+    Install the cross build files (headers, .a libs, .pxd files) to the
+    isolated environment's site packages.
 
     Parameters
     ----------
@@ -205,14 +147,39 @@ def _install_cross_build_files(path: str, unisolated: set[str]) -> None:
     unisolated
         The set of unisolated packages.
     """
-
-    sitepackagesdir = Path(_get_venv_paths(path)["purelib"])
+    _, _, purelib = _find_executable_and_scripts(venv_path)
+    sitepackagesdir = Path(purelib)
     for name in unisolated:
         base, files = get_unisolated_files(name)
-        for cross_build_file in files:
-            dest = sitepackagesdir / cross_build_file
+        for rel in files:
+            dest = sitepackagesdir / rel
             dest.parent.mkdir(parents=True, exist_ok=True)
-            shutil.copy(base / cross_build_file, dest)
+            shutil.copy(base / rel, dest)
+
+
+def remove_avoided_requirements(
+    requires: set[str], avoided_requirements: set[str] | list[str]
+) -> set[str]:
+    """
+    Remove requirements that are in the list of avoided requirements.
+
+    Parameters
+    ----------
+    requires
+        The set of requirements to filter.
+    avoided_requirements
+        The set of requirements to avoid.
+
+    Returns
+    -------
+    The filtered set of requirements.
+    """
+    for reqstr in list(requires):
+        req = Requirement(reqstr)
+        for avoid_name in set(avoided_requirements):
+            if avoid_name == req.name.lower():
+                requires.remove(reqstr)
+    return requires
 
 
 def install_reqs(
@@ -221,11 +188,8 @@ def install_reqs(
     IGNORED_BUILD_REQUIREMENTS = [
         pkg.strip() for pkg in get_host_build_flag("IGNORED_BUILD_REQUIREMENTS").split()
     ]
-    # replace oldest-supported-numpy and other unisolated packages before filtering
     reqs, unisolated = _replace_unisolated_packages(reqs, get_unisolated_packages())
-    reqs = _remove_avoided_requirements(
-        reqs, set(AVOIDED_REQUIREMENTS + IGNORED_BUILD_REQUIREMENTS)
-    )
+    reqs = remove_avoided_requirements(reqs, IGNORED_BUILD_REQUIREMENTS)
     # propagate PIP config from build_env to current environment
     with common.replace_env(
         os.environ | {k: v for k, v in build_env.items() if k.startswith("PIP")}

From fddf52090c7d274cdf09b714d779cd77ff902216 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 16:44:13 +0530
Subject: [PATCH 26/71] Early skip if no unisolated packages

---
 pyodide_build/pypabuild.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 4c017654..351289ef 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -147,6 +147,8 @@ def _install_cross_build_files(venv_path: str, unisolated: set[str]) -> None:
     unisolated
         The set of unisolated packages.
     """
+    if not unisolated:
+        return
     _, _, purelib = _find_executable_and_scripts(venv_path)
     sitepackagesdir = Path(purelib)
     for name in unisolated:

From 8c85dcfcac7861ae49275a8cb8516f5c0ed99793 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 16:45:11 +0530
Subject: [PATCH 27/71] Drop tests

---
 pyodide_build/tests/test_build_env.py | 15 --------
 pyodide_build/tests/test_pypabuild.py | 49 +--------------------------
 2 files changed, 1 insertion(+), 63 deletions(-)

diff --git a/pyodide_build/tests/test_build_env.py b/pyodide_build/tests/test_build_env.py
index 83926640..983fb676 100644
--- a/pyodide_build/tests/test_build_env.py
+++ b/pyodide_build/tests/test_build_env.py
@@ -116,21 +116,6 @@ def test_get_build_environment_vars_host_env(
         assert "PIP_CONSTRAINT" in e
         assert "RANDOM_ENV" not in e
 
-    def test_get_unisolated_packages(
-        self, dummy_xbuildenv, reset_env_vars, reset_cache
-    ):
-        expected = {"numpy", "scipy"}  # this relies on the dummy xbuildenv file
-        pkgs = build_env.get_unisolated_packages()
-        for pkg in expected:
-            assert pkg in pkgs
-
-    def test_get_unisolated_files(self, dummy_xbuildenv, reset_env_vars, reset_cache):
-        pkgs = build_env.get_unisolated_packages()
-
-        for pkg in pkgs:
-            files = build_env.get_unisolated_files(pkg)
-            assert files
-
 
 class TestWheelPlatform:
     def test_default_pyemscripten(self, dummy_xbuildenv, reset_env_vars, reset_cache):
diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py
index dda0186b..fb4f10a8 100644
--- a/pyodide_build/tests/test_pypabuild.py
+++ b/pyodide_build/tests/test_pypabuild.py
@@ -23,7 +23,7 @@ def install(self, reqs):
 
 
 def test_remove_avoided_requirements():
-    assert pypabuild._remove_avoided_requirements(
+    assert pypabuild.remove_avoided_requirements(
         {"foo", "bar", "baz"},
         {"foo", "bar", "qux"},
     ) == {"baz"}
@@ -109,53 +109,6 @@ def test_get_build_env(tmp_path, dummy_xbuildenv):
         assert "exports" in wasmcross_args
 
 
-def test_replace_unisolated_packages():
-    requires = {"foo", "bar<1.0", "baz==1.0", "qux"}
-    unisolated = {
-        "foo": "2.0",
-        "bar": "0.5",
-        "baz": "1.0",
-    }
-
-    new_requires, replaced = pypabuild._replace_unisolated_packages(
-        requires, unisolated
-    )
-    assert new_requires == {"foo==2.0", "bar==0.5", "baz==1.0", "qux"}
-    assert replaced == {"foo", "bar", "baz"}
-
-
-def test_replace_unisolated_packages_version_mismatch():
-    """
-    FIXME: This is not an ideal behavior, but for now wejust ignore the version mismatch.
-    """
-    requires = {"baz==1.0"}
-    unisolated = {
-        "baz": "1.1",
-    }
-
-    new_requires, replaced = pypabuild._replace_unisolated_packages(
-        requires, unisolated
-    )
-    assert new_requires == {"baz==1.1"}
-    assert replaced == {"baz"}
-
-
-def test_replace_unisoloated_packages_oldest_supported_numpy():
-    """
-    oldest-supported-numpy is a special case where we want to replace it with numpy instead.
-    """
-    requires = {"oldest-supported-numpy"}
-    unisolated = {
-        "numpy": "1.20",
-    }
-
-    new_requires, replaced = pypabuild._replace_unisolated_packages(
-        requires, unisolated
-    )
-    assert new_requires == {"numpy==1.20"}
-    assert replaced == {"numpy"}
-
-
 def _make_cpe(
     stdout: str | bytes | None = None, stderr: str | bytes | None = None
 ) -> subprocess.CalledProcessError:

From 0795637773f2f14cf59cb84ce5b1b7bdb393b87e Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 16:50:19 +0530
Subject: [PATCH 28/71] More changes

---
 pyodide_build/pypabuild.py            | 25 +++++++++++---
 pyodide_build/tests/test_pypabuild.py | 50 ++++++++++++++++++++++++++-
 2 files changed, 69 insertions(+), 6 deletions(-)

diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 351289ef..61687008 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -126,11 +126,26 @@ def _replace_unisolated_packages(
     new_reqs = reqs.copy()
     unisolated: set[str] = set()
     for reqstr in list(reqs):
-        name = Requirement(reqstr).name
-        if name in unisolated_packages:
-            new_reqs.discard(reqstr)
-            new_reqs.add(f"{name}=={unisolated_packages[name]}")
-            unisolated.add(name)
+        req = Requirement(reqstr)
+        for name, version in unisolated_packages.items():
+            if req.name == name:
+                # TODO: find a better way to handle this case
+                if not req.specifier.contains(version):
+                    print(
+                        f"WARNING: found build dependency {req} but the only supported cross-build version is {name}=={version}"
+                    )
+                    print(f"WARNING: using {name}=={version} instead")
+                new_reqs.discard(reqstr)
+                new_reqs.add(f"{name}=={version}")
+                unisolated.add(name)
+                break
+        else:
+            # oldest-supported-numpy is a meta package for numpy
+            # TODO: use dependency resolution instead of hardcoding this
+            if req.name == "oldest-supported-numpy" and "numpy" in unisolated_packages:
+                new_reqs.discard(reqstr)
+                new_reqs.add(f"numpy=={unisolated_packages['numpy']}")
+                unisolated.add("numpy")
     return new_reqs, unisolated
 
 
diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py
index fb4f10a8..59afb593 100644
--- a/pyodide_build/tests/test_pypabuild.py
+++ b/pyodide_build/tests/test_pypabuild.py
@@ -29,7 +29,55 @@ def test_remove_avoided_requirements():
     ) == {"baz"}
 
 
-def test_install_reqs(tmp_path, dummy_xbuildenv):
+def test_replace_unisolated_packages():
+    requires = {"foo", "bar<1.0", "baz==1.0", "qux"}
+    unisolated = {
+        "foo": "2.0",
+        "bar": "0.5",
+        "baz": "1.0",
+    }
+
+    new_requires, replaced = pypabuild._replace_unisolated_packages(
+        requires, unisolated
+    )
+    assert new_requires == {"foo==2.0", "bar==0.5", "baz==1.0", "qux"}
+    assert replaced == {"foo", "bar", "baz"}
+
+
+def test_replace_unisolated_packages_version_mismatch():
+    """
+    FIXME: This is not an ideal behavior, but for now we just ignore the version mismatch.
+    """
+    requires = {"baz==1.0"}
+    unisolated = {
+        "baz": "1.1",
+    }
+
+    new_requires, replaced = pypabuild._replace_unisolated_packages(
+        requires, unisolated
+    )
+    assert new_requires == {"baz==1.1"}
+    assert replaced == {"baz"}
+
+
+def test_replace_unisolated_packages_oldest_supported_numpy():
+    """
+    oldest-supported-numpy is a special case where we want to replace it with numpy instead.
+    """
+    requires = {"oldest-supported-numpy"}
+    unisolated = {
+        "numpy": "1.20",
+    }
+
+    new_requires, replaced = pypabuild._replace_unisolated_packages(
+        requires, unisolated
+    )
+    assert new_requires == {"numpy==1.20"}
+    assert replaced == {"numpy"}
+
+
+def test_install_reqs(tmp_path, dummy_xbuildenv, monkeypatch):
+    monkeypatch.setattr(pypabuild, "_install_cross_build_files", lambda *a, **kw: None)
     env = MockIsolatedEnv(tmp_path)
 
     reqs = {"foo", "bar", "baz"}

From f572a3d7fb17a8c8ea75ce95bf17fe20641a622b Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 16:53:01 +0530
Subject: [PATCH 29/71] Don't exclude integration tests from linting

---
 .pre-commit-config.yaml | 1 -
 1 file changed, 1 deletion(-)

diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 8c09c8be..beb01cbb 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,4 +1,3 @@
-exclude: (^integration_tests)
 default_language_version:
   python: "3.12"
 repos:

From 1e375532b3aecdeca34b5c6edf6a67e5af31ad1a Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 17:26:15 +0530
Subject: [PATCH 30/71] Put TODO above function

---
 pyodide_build/build_env.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py
index 913e1d37..cb9aa4c1 100644
--- a/pyodide_build/build_env.py
+++ b/pyodide_build/build_env.py
@@ -219,6 +219,8 @@ def get_hostsitepackages() -> str:
     return get_build_flag("HOSTSITEPACKAGES")
 
 
+# TODO: Remove this function (and use remote package index)
+# https://github.com/pyodide/pyodide-build/issues/43
 @functools.cache
 def get_unisolated_packages() -> dict[str, str]:
     """
@@ -233,8 +235,6 @@ def get_unisolated_packages() -> dict[str, str]:
     -------
     A dictionary of package names and versions.
     """
-    # TODO: Remove this function (and use remote package index)
-    # https://github.com/pyodide/pyodide-build/issues/43
     PYODIDE_ROOT = get_pyodide_root()
 
     unisolated_packages: dict[str, str] = {}

From 679daada2f17b480e672ba8384e1d3493e587339 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 17:33:33 +0530
Subject: [PATCH 31/71] Drop oldest-supported-numpy, it's deprecated now

---
 pyodide_build/constants.py            |  1 -
 pyodide_build/pypabuild.py            |  9 +--------
 pyodide_build/tests/test_pypabuild.py | 16 ----------------
 3 files changed, 1 insertion(+), 25 deletions(-)

diff --git a/pyodide_build/constants.py b/pyodide_build/constants.py
index 53d275d3..9f8903a5 100644
--- a/pyodide_build/constants.py
+++ b/pyodide_build/constants.py
@@ -4,5 +4,4 @@
 BASE_IGNORED_REQUIREMENTS: list[str] = [
     # mesonpy installs patchelf in linux platform but we don't want it.
     "patchelf",
-    "oldest-supported-numpy",
 ]
diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 61687008..5d9548b5 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -114,7 +114,7 @@ def _replace_unisolated_packages(
 
     Parameters
     ----------
-    requires
+    reqs
         The set of requirements to filter.
     unisolated_packages
         The dictionary of unisolated packages [name: version].
@@ -139,13 +139,6 @@ def _replace_unisolated_packages(
                 new_reqs.add(f"{name}=={version}")
                 unisolated.add(name)
                 break
-        else:
-            # oldest-supported-numpy is a meta package for numpy
-            # TODO: use dependency resolution instead of hardcoding this
-            if req.name == "oldest-supported-numpy" and "numpy" in unisolated_packages:
-                new_reqs.discard(reqstr)
-                new_reqs.add(f"numpy=={unisolated_packages['numpy']}")
-                unisolated.add("numpy")
     return new_reqs, unisolated
 
 
diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py
index 59afb593..e72fd95a 100644
--- a/pyodide_build/tests/test_pypabuild.py
+++ b/pyodide_build/tests/test_pypabuild.py
@@ -60,22 +60,6 @@ def test_replace_unisolated_packages_version_mismatch():
     assert replaced == {"baz"}
 
 
-def test_replace_unisolated_packages_oldest_supported_numpy():
-    """
-    oldest-supported-numpy is a special case where we want to replace it with numpy instead.
-    """
-    requires = {"oldest-supported-numpy"}
-    unisolated = {
-        "numpy": "1.20",
-    }
-
-    new_requires, replaced = pypabuild._replace_unisolated_packages(
-        requires, unisolated
-    )
-    assert new_requires == {"numpy==1.20"}
-    assert replaced == {"numpy"}
-
-
 def test_install_reqs(tmp_path, dummy_xbuildenv, monkeypatch):
     monkeypatch.setattr(pypabuild, "_install_cross_build_files", lambda *a, **kw: None)
     env = MockIsolatedEnv(tmp_path)

From f3bdb7df6645ae7f5079e99b6391d7df75fd9891 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 17:39:47 +0530
Subject: [PATCH 32/71] Drop `integration_tests/` changes, will test separately

---
 integration_tests/recipes/libboost/meta.yaml  |  37 --
 .../recipes/libf2c/extras/make.inc            |  80 ----
 integration_tests/recipes/libf2c/meta.yaml    |  46 ---
 .../libf2c/patches/0001-fix-arith.h.patch     |  30 --
 .../patches/0002-fix-f2clibs-build.patch      |  31 --
 .../0003-remove-redundant-symbols.patch       |  34 --
 .../patches/0004-correct-return-types.patch   |  81 ----
 ...5-Remove-symbols-defined-in-OpenBLAS.patch |  27 --
 .../patches/0006-adjust-ld-ar-ranlib.patch    |  33 --
 .../patches/0007-add-singlecomplex.patch      |  10 -
 .../recipes/libopenblas/meta.yaml             |  67 ----
 .../0001-Add-Wno-return-type-flag.patch       |  28 --
 ...ray-signature-with-scipy-expectation.patch |  25 --
 .../patches/0003-Skip-linktest.patch          |  75 ----
 integration_tests/recipes/numpy/test_numpy.py | 364 -----------------
 .../recipes/scipy/cmdline_test_file.py        |   8 -
 integration_tests/recipes/scipy/info.md       |  81 ----
 integration_tests/recipes/scipy/meta.yaml     | 204 ----------
 ...-Fix-dstevr-in-special-lapack_defs.h.patch |  32 --
 .../scipy/patches/0002-gemm_-no-const.patch   |  86 ----
 .../patches/0003-make-int-return-values.patch | 245 ------------
 .../scipy/patches/0004-Fix-fitpack.patch      | 112 ------
 .../scipy/patches/0005-Fix-gees-calls.patch   |  38 --
 ...enblas-with-modules-that-require-f2c.patch |  30 --
 .../patches/0007-Remove-chla_transtype.patch  |  27 --
 .../0008-Set-wrapper-return-type-to-int.patch |  25 --
 ...nvert-return-value-of-SUPERLU_MALLOC.patch |  76 ----
 ...ove-dummy-argument-from-larf-wrapper.patch |  46 ---
 .../recipes/scipy/scipy-conftest.py           | 376 ------------------
 integration_tests/recipes/scipy/test_scipy.py | 214 ----------
 30 files changed, 2568 deletions(-)
 delete mode 100644 integration_tests/recipes/libboost/meta.yaml
 delete mode 100644 integration_tests/recipes/libf2c/extras/make.inc
 delete mode 100644 integration_tests/recipes/libf2c/meta.yaml
 delete mode 100644 integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch
 delete mode 100644 integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch
 delete mode 100644 integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch
 delete mode 100644 integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch
 delete mode 100644 integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch
 delete mode 100644 integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch
 delete mode 100644 integration_tests/recipes/libf2c/patches/0007-add-singlecomplex.patch
 delete mode 100644 integration_tests/recipes/libopenblas/meta.yaml
 delete mode 100644 integration_tests/recipes/libopenblas/patches/0001-Add-Wno-return-type-flag.patch
 delete mode 100644 integration_tests/recipes/libopenblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
 delete mode 100644 integration_tests/recipes/libopenblas/patches/0003-Skip-linktest.patch
 delete mode 100644 integration_tests/recipes/numpy/test_numpy.py
 delete mode 100644 integration_tests/recipes/scipy/cmdline_test_file.py
 delete mode 100644 integration_tests/recipes/scipy/info.md
 delete mode 100644 integration_tests/recipes/scipy/meta.yaml
 delete mode 100644 integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0002-gemm_-no-const.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0003-make-int-return-values.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0004-Fix-fitpack.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0005-Fix-gees-calls.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0006-Link-openblas-with-modules-that-require-f2c.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0007-Remove-chla_transtype.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0008-Set-wrapper-return-type-to-int.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0010-Explicitly-convert-return-value-of-SUPERLU_MALLOC.patch
 delete mode 100644 integration_tests/recipes/scipy/patches/0011-MAINT-linalg-Remove-dummy-argument-from-larf-wrapper.patch
 delete mode 100644 integration_tests/recipes/scipy/scipy-conftest.py
 delete mode 100644 integration_tests/recipes/scipy/test_scipy.py

diff --git a/integration_tests/recipes/libboost/meta.yaml b/integration_tests/recipes/libboost/meta.yaml
deleted file mode 100644
index 671e5047..00000000
--- a/integration_tests/recipes/libboost/meta.yaml
+++ /dev/null
@@ -1,37 +0,0 @@
-package:
-  name: libboost
-  version: 1.84.0
-  tag:
-    - library
-    - static_library
-source:
-  url: https://github.com/boostorg/boost/releases/download/boost-1.84.0/boost-1.84.0.tar.gz
-  sha256: 4d27e9efed0f6f152dc28db6430b9d3dfb40c0345da7342eaa5a987dde57bd95
-
-build:
-  type: static_library
-  script: |
-    export INSTALL_DIR=${WASM_LIBRARY_DIR}
-    ./bootstrap.sh --prefix=${INSTALL_DIR}
-
-    # https://github.com/emscripten-core/emscripten/issues/17052
-    # Without this, boost outputs WASM modules not static library archives as an output.
-    # I don't understand why... the jam file used by boost is quite hard to understand.
-    printf "using clang : emscripten : emcc : emar emranlib emlink ;" | tee -a ./project-config.jam
-
-    ./b2 variant=release toolset=clang-emscripten link=static threading=single \
-      --with-date_time --with-filesystem \
-      --with-system --with-regex --with-chrono --with-random --with-program_options --disable-icu \
-      cxxflags="$SIDE_MODULE_CXXFLAGS -fwasm-exceptions -DBOOST_SP_DISABLE_THREADS=1" \
-      cflags="$SIDE_MODULE_CFLAGS -fwasm-exceptions -DBOOST_SP_DISABLE_THREADS=1" \
-      linkflags="-fpic $SIDE_MODULE_LDFLAGS" \
-      --layout=system -j"${PYODIDE_JOBS:-3}" --prefix=${INSTALL_DIR} \
-      install
-
-about:
-  home: https://www.boost.org/
-  summary: Free peer-reviewed portable C++ source libraries.
-  license: Boost
-extra:
-  recipe-maintainers:
-    - johnwason
diff --git a/integration_tests/recipes/libf2c/extras/make.inc b/integration_tests/recipes/libf2c/extras/make.inc
deleted file mode 100644
index 7eaae7b5..00000000
--- a/integration_tests/recipes/libf2c/extras/make.inc
+++ /dev/null
@@ -1,80 +0,0 @@
-# -*- Makefile -*-
-####################################################################
-#  LAPACK make include file.                                       #
-#  LAPACK, Version 3.2.1                                           #
-#  June 2009		                                               #
-####################################################################
-#
-# See the INSTALL/ directory for more examples.
-#
-SHELL = /usr/bin/env sh
-#
-#  The machine (platform) identifier to append to the library names
-#
-# WA for WebAssembly
-PLAT = _WA
-#
-#  Modify the FORTRAN and OPTS definitions to refer to the
-#  compiler and desired compiler options for your machine.  NOOPT
-#  refers to the compiler options desired when NO OPTIMIZATION is
-#  selected.  Define LOADER and LOADOPTS to refer to the loader
-#  and desired load options for your machine.
-#
-#######################################################
-# This is used to compile C library
-#CC        = gcc  # inherit $CC from emmake
-# if no wrapping of the blas library is needed, uncomment next line
-#CC        = gcc -DNO_BLAS_WRAP
-CFLAGS    = -O3 -I$(TOPDIR)/INCLUDE -fPIC -DNO_BLAS_WRAP
-LDFLAGS	  = -O3
-LOADER    = $(CC)
-LOADOPTS  =
-NOOPT     = -O0 -I$(TOPDIR)/INCLUDE -fPIC
-DRVCFLAGS = $(CFLAGS)
-F2CCFLAGS = $(CFLAGS)
-#######################################################################
-
-#
-# Timer for the SECOND and DSECND routines
-#
-# Default : SECOND and DSECND will use a call to the EXTERNAL FUNCTION ETIME
-# TIMER    = EXT_ETIME
-# For RS6K : SECOND and DSECND will use a call to the EXTERNAL FUNCTION ETIME_
-# TIMER    = EXT_ETIME_
-# For gfortran compiler: SECOND and DSECND will use a call to the INTERNAL FUNCTION ETIME
-# TIMER    = INT_ETIME
-# If your Fortran compiler does not provide etime (like Nag Fortran Compiler, etc...)
-# SECOND and DSECND will use a call to the Fortran standard INTERNAL FUNCTION CPU_TIME
-TIMER    = INT_CPU_TIME
-# If neither of this works...you can use the NONE value... In that case, SECOND and DSECND will always return 0
-# TIMER     = NONE
-#
-#  The archiver and the flag(s) to use when building archive (library)
-#  If you system has no ranlib, set RANLIB = echo.
-#
-ARCH     = $(AR)
-ARCHFLAGS= cr
-#RANLIB   = ranlib
-#
-#  The location of BLAS library for linking the testing programs.
-#  The target's machine-specific, optimized BLAS library should be
-#  used whenever possible.
-#
-BLASLIB      = ../../blas$(PLAT).a
-#
-#  Location of the extended-precision BLAS (XBLAS) Fortran library
-#  used for building and testing extended-precision routines.  The
-#  relevant routines will be compiled and XBLAS will be linked only if
-#  USEXBLAS is defined.
-#
-# USEXBLAS    = Yes
-XBLASLIB     =
-# XBLASLIB    = -lxblas
-#
-#  Names of generated libraries.
-#
-LAPACKLIB    = lapack$(PLAT).a
-F2CLIB       = ../../F2CLIBS/libf2c.a
-TMGLIB       = tmglib$(PLAT).a
-EIGSRCLIB    = eigsrc$(PLAT).a
-LINSRCLIB    = linsrc$(PLAT).a
diff --git a/integration_tests/recipes/libf2c/meta.yaml b/integration_tests/recipes/libf2c/meta.yaml
deleted file mode 100644
index 45858b5a..00000000
--- a/integration_tests/recipes/libf2c/meta.yaml
+++ /dev/null
@@ -1,46 +0,0 @@
-# We still download the full CLAPACK but we are only using the libf2c part of CLAPACK.
-# libf2c part is needed for the f2ced Fortran files in scipy for example to
-# define things like pow_dd, i_len, etc...
-#
-# Note f2clib package only creates f2clib.a, and f2clib.a symbols are added to
-# libopenblas.so in the OpenBLAS meta.yaml.
-package:
-  name: libf2c
-  version: CLAPACK-3.2.1
-  tag:
-    - library
-source:
-  sha256: 6dc4c382164beec8aaed8fd2acc36ad24232c406eda6db462bd4c41d5e455fac
-  url: http://www.netlib.org/clapack/clapack.tgz
-  extract_dir: CLAPACK-3.2.1
-  patches:
-    - patches/0001-fix-arith.h.patch
-    - patches/0002-fix-f2clibs-build.patch
-    - patches/0003-remove-redundant-symbols.patch
-    - patches/0004-correct-return-types.patch
-    - patches/0005-Remove-symbols-defined-in-OpenBLAS.patch
-    # In CLAPACK's F2CLIBS/libf2c Makefile, some commands are mistakenly (?) hardcoded
-    # instead of using the right variables
-    - patches/0006-adjust-ld-ar-ranlib.patch
-    - patches/0007-add-singlecomplex.patch
-
-  extras:
-    - [extras/make.inc, make.inc]
-
-build:
-  type: static_library
-  script: |
-    # The archive's contents have default permission 0750. If we use docker
-    # to build, then we will not own the contents in the host, which means
-    # we cannot navigate into the folder. Setting it to 0750 makes it
-    # easier to debug.
-    chmod -R o+rx .
-
-    ARCH="emar" \
-    emmake make -j ${PYODIDE_JOBS:-3} f2clib
-    mkdir -p ${WASM_LIBRARY_DIR}/{lib,include}
-    cp INCLUDE/f2c.h ${WASM_LIBRARY_DIR}/include
-    cp F2CLIBS/libf2c.a ${WASM_LIBRARY_DIR}/lib
-about:
-  home: https://www.netlib.org/clapack/
-  license: BSD-3-Clause
diff --git a/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch b/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch
deleted file mode 100644
index 7773825a..00000000
--- a/integration_tests/recipes/libf2c/patches/0001-fix-arith.h.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 01990867ee7a641078505efba367a413a97f7802 Mon Sep 17 00:00:00 2001
-From: Michael Droettboom 
-Date: Fri, 18 Mar 2022 19:59:25 -0700
-Subject: [PATCH 1/5] fix arith.h
-
-arith.h is a file generated at build time by compiling and running a C program.
-Since we use emscripten to build throughout, the C program becomes a wasm file
-and we call it differently.
----
- F2CLIBS/libf2c/Makefile | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/F2CLIBS/libf2c/Makefile b/F2CLIBS/libf2c/Makefile
-index 0a3ed0d..a473ed8 100644
---- a/F2CLIBS/libf2c/Makefile
-+++ b/F2CLIBS/libf2c/Makefile
-@@ -173,8 +173,8 @@ xwsne.o:	fmt.h
- arith.h: arithchk.c
- 	$(CC) $(CFLAGS) -DNO_FPINIT arithchk.c -lm ||\
- 	 $(CC) -DNO_LONG_LONG $(CFLAGS) -DNO_FPINIT arithchk.c -lm
--	./a.out >arith.h
--	rm -f a.out arithchk.o
-+	node a.out.js >arith.h
-+	rm -f a.out.js a.out.wasm
- 
- check:
- 	xsum Notice README abort_.c arithchk.c backspac.c c_abs.c c_cos.c \
--- 
-2.25.1
-
diff --git a/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch b/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch
deleted file mode 100644
index 89d94e5d..00000000
--- a/integration_tests/recipes/libf2c/patches/0002-fix-f2clibs-build.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From d88133066f9f6312145c1186116fdb6446d3f7a5 Mon Sep 17 00:00:00 2001
-From: Michael Droettboom 
-Date: Fri, 18 Mar 2022 20:00:51 -0700
-Subject: [PATCH 2/5] fix f2clibs build
-
-emscripten produces LLVM bitcode here, not genuine object files, so it doesn't
-make sense to strip symbols.
-
-(It would also fail because emcc uses the file extension to determine what kind
-of object to output, and .xxx is not a recognized extension; this is the error
-message you would receive if you try to run the commands)
----
- F2CLIBS/libf2c/Makefile | 2 --
- 1 file changed, 2 deletions(-)
-
-diff --git a/F2CLIBS/libf2c/Makefile b/F2CLIBS/libf2c/Makefile
-index a473ed8..e51d826 100644
---- a/F2CLIBS/libf2c/Makefile
-+++ b/F2CLIBS/libf2c/Makefile
-@@ -19,8 +19,6 @@ include ../../make.inc
- # compile, then strip unnecessary symbols
- .c.o:
- 	$(CC) -c -DSkip_f2c_Undefs $(CFLAGS) $*.c
--	ld -r -x -o $*.xxx $*.o
--	mv $*.xxx $*.o
- ## Under Solaris (and other systems that do not understand ld -x),
- ## omit -x in the ld line above.
- ## If your system does not have the ld command, comment out
--- 
-2.25.1
-
diff --git a/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch b/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch
deleted file mode 100644
index bfd7257f..00000000
--- a/integration_tests/recipes/libf2c/patches/0003-remove-redundant-symbols.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 78ff0cec961d9eb4e94193995fe151e1ecdae9df Mon Sep 17 00:00:00 2001
-From: Roman Yurchak 
-Date: Fri, 18 Mar 2022 20:01:39 -0700
-Subject: [PATCH 3/5] remove redundant symbols
-
-Remove a few symbols from LAPACK that are redundantly defined with BLAS or are
-ported in scipy. It wouldn't be an issue if we were linking dynamically, but
-because of static linking otherwise we get errors at link time about symbols
-defined twice.
-
- - Roman Yurchak (https://github.com/pyodide/pyodide/pull/238)
----
- SRC/Makefile | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/SRC/Makefile b/SRC/Makefile
-index 5f1eb22..32e669b 100644
---- a/SRC/Makefile
-+++ b/SRC/Makefile
-@@ -48,9 +48,9 @@ include ../make.inc
- #
- #######################################################################
- 
--ALLAUX = maxloc.o ilaenv.o ieeeck.o lsamen.o xerbla.o xerbla_array.o iparmq.o	\
-+ALLAUX = maxloc.o ilaenv.o ieeeck.o lsamen.o iparmq.o	\
-     ilaprec.o ilatrans.o ilauplo.o iladiag.o chla_transtype.o \
--    ../INSTALL/ilaver.o ../INSTALL/lsame.o
-+    ../INSTALL/ilaver.o
- 
- ALLXAUX =
- 
--- 
-2.25.1
-
diff --git a/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch b/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch
deleted file mode 100644
index 5d95f705..00000000
--- a/integration_tests/recipes/libf2c/patches/0004-correct-return-types.patch
+++ /dev/null
@@ -1,81 +0,0 @@
-From 572a3e20ba040b4f29bbef97a9db6658c10077d3 Mon Sep 17 00:00:00 2001
-From: Joe Marshall 
-Date: Fri, 18 Mar 2022 20:02:42 -0700
-Subject: [PATCH 4/5] correct return types
-
-Make return types to fortran subroutines consistently be int. Some functions are defined within clapack as variously
-void and int return. Normal C compilers don't care, but emscripten is strict about return values.
----
- F2CLIBS/libf2c/ef1asc_.c | 2 +-
- F2CLIBS/libf2c/f2ch.add  | 4 ++--
- F2CLIBS/libf2c/s_cat.c   | 6 +++---
- F2CLIBS/libf2c/s_copy.c  | 4 ++--
- 4 files changed, 8 insertions(+), 8 deletions(-)
-
-diff --git a/F2CLIBS/libf2c/ef1asc_.c b/F2CLIBS/libf2c/ef1asc_.c
-index 70be0bc..b2a82a2 100644
---- a/F2CLIBS/libf2c/ef1asc_.c
-+++ b/F2CLIBS/libf2c/ef1asc_.c
-@@ -13,7 +13,7 @@ extern "C" {
- extern VOID s_copy();
- ef1asc_(a, la, b, lb) ftnint *a, *b; ftnlen *la, *lb;
- #else
--extern void s_copy(char*,char*,ftnlen,ftnlen);
-+extern int s_copy(char*,char*,ftnlen,ftnlen);
- int ef1asc_(ftnint *a, ftnlen *la, ftnint *b, ftnlen *lb)
- #endif
- {
-diff --git a/F2CLIBS/libf2c/f2ch.add b/F2CLIBS/libf2c/f2ch.add
-index a2acc17..f3f0466 100644
---- a/F2CLIBS/libf2c/f2ch.add
-+++ b/F2CLIBS/libf2c/f2ch.add
-@@ -124,9 +124,9 @@ extern double r_sinh(float *);
- extern double r_sqrt(float *);
- extern double r_tan(float *);
- extern double r_tanh(float *);
--extern void s_cat(char *, char **, integer *, integer *, ftnlen);
-+extern int s_cat(char *, char **, integer *, integer *, ftnlen);
- extern integer s_cmp(char *, char *, ftnlen, ftnlen);
--extern void s_copy(char *, char *, ftnlen, ftnlen);
-+extern int s_copy(char *, char *, ftnlen, ftnlen);
- extern int s_paus(char *, ftnlen);
- extern integer s_rdfe(cilist *);
- extern integer s_rdue(cilist *);
-diff --git a/F2CLIBS/libf2c/s_cat.c b/F2CLIBS/libf2c/s_cat.c
-index 8d92a63..54c4ff1 100644
---- a/F2CLIBS/libf2c/s_cat.c
-+++ b/F2CLIBS/libf2c/s_cat.c
-@@ -28,11 +28,11 @@ extern
- extern "C" {
- #endif
- 
-- VOID
-+ 
- #ifdef KR_headers
--s_cat(lp, rpp, rnp, np, ll) char *lp, *rpp[]; ftnint rnp[], *np; ftnlen ll;
-+int s_cat(lp, rpp, rnp, np, ll) char *lp, *rpp[]; ftnint rnp[], *np; ftnlen ll;
- #else
--s_cat(char *lp, char *rpp[], ftnint rnp[], ftnint *np, ftnlen ll)
-+int s_cat(char *lp, char *rpp[], ftnint rnp[], ftnint *np, ftnlen ll)
- #endif
- {
- 	ftnlen i, nc;
-diff --git a/F2CLIBS/libf2c/s_copy.c b/F2CLIBS/libf2c/s_copy.c
-index 9dacfc7..8d8963f 100644
---- a/F2CLIBS/libf2c/s_copy.c
-+++ b/F2CLIBS/libf2c/s_copy.c
-@@ -12,9 +12,9 @@ extern "C" {
- /* assign strings:  a = b */
- 
- #ifdef KR_headers
--VOID s_copy(a, b, la, lb) register char *a, *b; ftnlen la, lb;
-+int s_copy(a, b, la, lb) register char *a, *b; ftnlen la, lb;
- #else
--void s_copy(register char *a, register char *b, ftnlen la, ftnlen lb)
-+int s_copy(register char *a, register char *b, ftnlen la, ftnlen lb)
- #endif
- {
- 	register char *aend, *bend;
--- 
-2.25.1
-
diff --git a/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch b/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch
deleted file mode 100644
index 7dce211b..00000000
--- a/integration_tests/recipes/libf2c/patches/0005-Remove-symbols-defined-in-OpenBLAS.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From eaf5c5db6e956036869255cb51831e720474d01d Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= 
-Date: Fri, 7 Apr 2023 15:20:18 +0200
-Subject: [PATCH 5/5] Remove symbols defined in OpenBLAS
-
----
- F2CLIBS/libf2c/Makefile | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/F2CLIBS/libf2c/Makefile b/F2CLIBS/libf2c/Makefile
-index 57eff0d..136050f 100644
---- a/F2CLIBS/libf2c/Makefile
-+++ b/F2CLIBS/libf2c/Makefile
-@@ -31,8 +31,8 @@ MISC =	f77vers.o i77vers.o main.o s_rnge.o abort_.o exit_.o getarg_.o iargc_.o\
- 	getenv_.o signal_.o s_stop.o s_paus.o system_.o cabs.o ctype.o\
- 	derf_.o derfc_.o erf_.o erfc_.o sig_die.o uninit.o
- POW =	pow_ci.o pow_dd.o pow_di.o pow_hh.o pow_ii.o pow_ri.o pow_zi.o pow_zz.o
--CX =	c_abs.o c_cos.o c_div.o c_exp.o c_log.o c_sin.o c_sqrt.o
--DCX =	z_abs.o z_cos.o z_div.o z_exp.o z_log.o z_sin.o z_sqrt.o
-+CX =	c_cos.o c_div.o c_exp.o c_log.o c_sin.o c_sqrt.o
-+DCX =	z_cos.o z_div.o z_exp.o z_log.o z_sin.o z_sqrt.o
- REAL =	r_abs.o r_acos.o r_asin.o r_atan.o r_atn2.o r_cnjg.o r_cos.o\
- 	r_cosh.o r_dim.o r_exp.o r_imag.o r_int.o\
- 	r_lg10.o r_log.o r_mod.o r_nint.o r_sign.o\
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch b/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch
deleted file mode 100644
index 336f3761..00000000
--- a/integration_tests/recipes/libf2c/patches/0006-adjust-ld-ar-ranlib.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-Index: CLAPACK-3.2.1/F2CLIBS/libf2c/Makefile
-===================================================================
---- CLAPACK-3.2.1.orig/F2CLIBS/libf2c/Makefile
-+++ CLAPACK-3.2.1/F2CLIBS/libf2c/Makefile
-@@ -70,8 +70,8 @@ OFILES = $(MISC) $(POW) $(CX) $(DCX) $(R
- all: f2c.h signal1.h sysdep1.h libf2c.a clapack_install
- 
- libf2c.a: $(OFILES)
--	ar r libf2c.a $?
--	-ranlib libf2c.a
-+	$(ARCH) r libf2c.a $?
-+	$(RANLIB) libf2c.a
- 
- ## Shared-library variant: the following rule works on Linux
- ## systems.  Details are system-dependent.  Under Linux, -fPIC
-@@ -80,7 +80,7 @@ libf2c.a: $(OFILES)
- ## of "cc -shared".
- 
- libf2c.so: $(OFILES)
--	cc -shared -o libf2c.so $(OFILES)
-+	$(CC) -shared -o libf2c.so $(OFILES)
- 
- ### If your system lacks ranlib, you don't need it; see README.
- 
-@@ -117,7 +117,7 @@ sysdep1.h: sysdep1.h0
- 
- install: libf2c.a
- 	cp libf2c.a $(LIBDIR)
--	-ranlib $(LIBDIR)/libf2c.a
-+	$(RANLIB) $(LIBDIR)/libf2c.a
- 
- clapack_install: libf2c.a
- 	mv libf2c.a ..
diff --git a/integration_tests/recipes/libf2c/patches/0007-add-singlecomplex.patch b/integration_tests/recipes/libf2c/patches/0007-add-singlecomplex.patch
deleted file mode 100644
index 982d3065..00000000
--- a/integration_tests/recipes/libf2c/patches/0007-add-singlecomplex.patch
+++ /dev/null
@@ -1,10 +0,0 @@
---- a/INCLUDE/f2c.h
-+++ b/INCLUDE/f2c.h
-@@ -14,6 +14,7 @@ typedef short int shortint;
- typedef float real;
- typedef double doublereal;
- typedef struct { real r, i; } complex;
-+typedef struct { real r, i; } singlecomplex;
- typedef struct { doublereal r, i; } doublecomplex;
- typedef long int logical;
- typedef short int shortlogical;
diff --git a/integration_tests/recipes/libopenblas/meta.yaml b/integration_tests/recipes/libopenblas/meta.yaml
deleted file mode 100644
index 0fb20390..00000000
--- a/integration_tests/recipes/libopenblas/meta.yaml
+++ /dev/null
@@ -1,67 +0,0 @@
-package:
-  name: libopenblas
-  version: 0.3.28
-  tag:
-    - core
-    - library
-    - shared_library
-source:
-  sha256: f1003466ad074e9b0c8d421a204121100b0751c96fc6fcf3d1456bd12f8a00a1
-  url: https://github.com/OpenMathLib/OpenBLAS/releases/download/v0.3.28/OpenBLAS-0.3.28.tar.gz
-  patches:
-    - patches/0001-Add-Wno-return-type-flag.patch
-    - patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
-    - patches/0003-Skip-linktest.patch
-
-build:
-  type: shared_library
-  script: |
-    # seems like .zip does not maintain executable flags, need to reset these
-    chmod u+x c_check
-    chmod u+x f_check
-    chmod u+x exports/gensymbol
-    # Replace void returns by int returns
-    sed -ri 's/void(\s+)BLASFUNC/int\1BLASFUNC/g' common_interface.h
-    sed -ri 's/void(\s+)cblas_/int\1cblas_/g' cblas.h ctest/*.c
-    sed -ri 's/void(\s+)(C?NAME)/int\1\2/g' interface/*.c
-    sed -ri 's/((extern)?.+) void ([a-z0-9]+_)/\1\2 int \3/g' lapack-netlib/SRC/*.c \
-        lapack-netlib/SRC/DEPRECATED/*.c
-    # For some functions (mostly handling complex I think) f2c actually
-    # generate a function that returns void so I need to revert the void to int
-    # change the previous line does.
-    sed -ri 's@int ([cz](dotc|dotu|ladiv))@void \1@g' lapack-netlib/SRC/*.c\
-        lapack-netlib/SRC/DEPRECATED/*.c
-
-    # When TARGET=RISCV64_GENERIC, OpenBLAS adds `-march` and `-mabi` flags to the compiler.
-    # However, they are not supported by Emscripten, and started to cause build failures from recent Emscripten versions (>4.X).
-    sed -i 's@ifeq ($(CORE), RISCV64_GENERIC)@ifeq ($(CORE), NOT_RISCV64_GENERIC)@g' Makefile.riscv64
-    sed -i 's@ifeq ($(TARGET), RISCV64_GENERIC)@ifeq ($(TARGET), NOT_RISCV64_GENERIC)@g' Makefile.prebuild
-
-    emmake make libs shared \
-        BINARY=32 \
-        CC="emcc -msimd128" \
-        HOSTCC=gcc \
-        TARGET=RISCV64_GENERIC \
-        NOFORTRAN=1 NO_LAPACKE=1 \
-        USE_THREAD=0 \
-        LDFLAGS="${SIDE_MODULE_LDFLAGS}"
-    mkdir -p dist
-
-    # Add libf2c symbols to libopenblas.so
-    emcc ${WASM_LIBRARY_DIR}/lib/libf2c.a libopenblas.a \
-        ${SIDE_MODULE_LDFLAGS} \
-        -msimd128 \
-        -o libopenblas.so
-
-    cp libopenblas.so dist
-    emmake make install PREFIX=${WASM_LIBRARY_DIR}
-    # We need to copy the shared library again as the make install
-    # does not know we've modified the binary with libf2c symbols.
-    cp dist/libopenblas.so ${WASM_LIBRARY_DIR}/lib/libopenblas.so
-
-requirements:
-  host:
-    - libf2c
-about:
-  home: https://www.openblas.net/
-  license: BSD-3-Clause
diff --git a/integration_tests/recipes/libopenblas/patches/0001-Add-Wno-return-type-flag.patch b/integration_tests/recipes/libopenblas/patches/0001-Add-Wno-return-type-flag.patch
deleted file mode 100644
index 8dcfc60a..00000000
--- a/integration_tests/recipes/libopenblas/patches/0001-Add-Wno-return-type-flag.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 3111f04db010f53a2634db4f4e8e35a2d9a2957b Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= 
-Date: Fri, 9 Dec 2022 16:40:13 +0100
-Subject: [PATCH 1/3] Add -Wno-return-type flag
-
-This is needed because we are changing many signatures to return int instead of
-void with some regex expressions but we are not modifying the returned value
- which would potentially be a lot more tricky.
----
- Makefile.rule | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/Makefile.rule b/Makefile.rule
-index daf2d958d..6595d4271 100644
---- a/Makefile.rule
-+++ b/Makefile.rule
-@@ -231,7 +231,7 @@ NO_AFFINITY = 1
- # Common Optimization Flag;
- # The default -O2 is enough.
- # Flags for POWER8 are defined in Makefile.power. Don't modify COMMON_OPT
--# COMMON_OPT = -O2
-+COMMON_OPT = -O2 -Wno-return-type
- 
- # gfortran option for LAPACK to improve thread-safety
- # It is enabled by default in Makefile.system for gfortran
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/libopenblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch b/integration_tests/recipes/libopenblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
deleted file mode 100644
index 09a56911..00000000
--- a/integration_tests/recipes/libopenblas/patches/0002-Align-xerbla_array-signature-with-scipy-expectation.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From 8ce75f14b82ed67eaf0eaceea0c8092851af00c2 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= 
-Date: Fri, 7 Apr 2023 10:27:59 +0200
-Subject: [PATCH 2/3] Align xerbla_array signature with scipy expectation
-
----
- lapack-netlib/SRC/xerbla_array.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/lapack-netlib/SRC/xerbla_array.c b/lapack-netlib/SRC/xerbla_array.c
-index fe7d6d898..74d3ca96a 100644
---- a/lapack-netlib/SRC/xerbla_array.c
-+++ b/lapack-netlib/SRC/xerbla_array.c
-@@ -600,7 +600,7 @@ array.f"> */
- 
- /*  ===================================================================== */
- /* Subroutine */ void xerbla_array_(char *srname_array__, integer *
--	srname_len__, integer *info, integer srname_array_len)
-+	srname_len__, integer *info)
- {
-     /* System generated locals */
-     integer i__1, i__2, i__3;
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/libopenblas/patches/0003-Skip-linktest.patch b/integration_tests/recipes/libopenblas/patches/0003-Skip-linktest.patch
deleted file mode 100644
index 2f51aa2e..00000000
--- a/integration_tests/recipes/libopenblas/patches/0003-Skip-linktest.patch
+++ /dev/null
@@ -1,75 +0,0 @@
-From e66fa1d85166c1bd27a52d09221f5b5575ba63ca Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Wed, 22 Jan 2025 13:52:55 +0100
-Subject: [PATCH 3/3] Skip linktest
-
----
- exports/Makefile | 17 ++++++++---------
- 1 file changed, 8 insertions(+), 9 deletions(-)
-
-diff --git a/exports/Makefile b/exports/Makefile
-index 7682f851d..86b2cd2f4 100644
---- a/exports/Makefile
-+++ b/exports/Makefile
-@@ -184,24 +184,24 @@ ifeq ($(F_COMPILER), INTEL)
- 	$(FC) $(FFLAGS) $(LDFLAGS) -shared -o ../$(LIBSONAME) \
- 	-Wl,--whole-archive $< -Wl,--no-whole-archive \
- 	-Wl,-soname,$(INTERNALNAME) $(EXTRALIB)
--	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
-+	echo OK.
- else ifeq ($(F_COMPILER), FLANG)
- 	$(FC) $(FFLAGS) $(LDFLAGS) -shared -o ../$(LIBSONAME) \
- 	-Wl,--whole-archive $< -Wl,--no-whole-archive \
- 	-Wl,-soname,$(INTERNALNAME) $(EXTRALIB)
--	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
-+	echo OK.
- else
- ifneq ($(C_COMPILER), LSB)
- 	$(CC) $(CFLAGS) $(LDFLAGS) -shared -o ../$(LIBSONAME) \
- 	-Wl,--whole-archive $< -Wl,--no-whole-archive \
- 	-Wl,-soname,$(INTERNALNAME) $(EXTRALIB)
--	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
-+	echo OK.
- else
- #for LSB
- 	env LSBCC_SHAREDLIBS=gfortran $(CC) $(CFLAGS) $(LDFLAGS) -shared -o ../$(LIBSONAME) \
- 	-Wl,--whole-archive $< -Wl,--no-whole-archive \
- 	-Wl,-soname,$(INTERNALNAME) $(EXTRALIB)
--	$(FC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
-+	echo OK.
- endif
- endif
- 	rm -f linktest
-@@ -223,7 +223,7 @@ endif
- 	$(CC) $(CFLAGS) $(LDFLAGS)  -shared -o ../$(LIBSONAME) \
- 	-Wl,--whole-archive $< -Wl,--no-whole-archive \
- 	$(FEXTRALIB) $(EXTRALIB)
--	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
-+	echo OK.
- 	rm -f linktest
- 
- endif
-@@ -241,7 +241,7 @@ ifeq ($(OSNAME), SunOS)
- so : ../$(LIBSONAME)
- 	$(CC) $(CFLAGS) $(LDFLAGS)  -shared -o ../$(LIBSONAME) \
- 	-Wl,--whole-archive ../$(LIBNAME) -Wl,--no-whole-archive $(EXTRALIB)
--	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) $(FEXTRALIB) && echo OK.
-+	echo OK.
- 	rm -f linktest
- 
- endif
-@@ -283,9 +283,8 @@ objcopy.def : $(GENSYM) ../Makefile.system ../getarch.c
- objconv.def : $(GENSYM) ../Makefile.system ../getarch.c
- 	./$(GENSYM) objconv $(ARCH) "$(BU)" $(EXPRECISION) $(NO_CBLAS)  $(NO_LAPACK) $(NO_LAPACKE) $(NEED2UNDERSCORES) $(ONLY_CBLAS) "$(SYMBOLPREFIX)" "$(SYMBOLSUFFIX)" $(BUILD_LAPACK_DEPRECATED) $(BUILD_BFLOAT16) $(BUILD_SINGLE) $(BUILD_DOUBLE) $(BUILD_COMPLEX) $(BUILD_COMPLEX16) > $(@F)
- 
--test : linktest.c
--	$(CC) $(CFLAGS) $(LDFLAGS) -w -o linktest linktest.c ../$(LIBSONAME) -lm && echo OK.
--	rm -f linktest
-+test :
-+	echo OK.
- 
- linktest.c : $(GENSYM) ../Makefile.system ../getarch.c
- 	./$(GENSYM) linktest  $(ARCH) "$(BU)" $(EXPRECISION) $(NO_CBLAS) $(NO_LAPACK) $(NO_LAPACKE) $(NEED2UNDERSCORES) $(ONLY_CBLAS) "$(SYMBOLPREFIX)" "$(SYMBOLSUFFIX)" $(BUILD_LAPACK_DEPRECATED) $(BUILD_BFLOAT16) $(BUILD_SINGLE) $(BUILD_DOUBLE) $(BUILD_COMPLEX) $(BUILD_COMPLEX16) > linktest.c
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/numpy/test_numpy.py b/integration_tests/recipes/numpy/test_numpy.py
deleted file mode 100644
index c446b936..00000000
--- a/integration_tests/recipes/numpy/test_numpy.py
+++ /dev/null
@@ -1,364 +0,0 @@
-import pytest
-from pytest_pyodide import run_in_pyodide
-
-
-def test_numpy(selenium):
-    selenium.load_package("numpy")
-    selenium.run(
-        """
-        import numpy
-        x = numpy.ones((32, 64))
-        """
-    )
-    selenium.run_js(
-        """
-        let xpy = pyodide.runPython('x');
-        self.x = xpy.toJs();
-        xpy.destroy();
-        """
-    )
-    assert selenium.run_js("return x.length === 32")
-    for i in range(32):
-        assert selenium.run_js(f"return x[{i}].length == 64")
-        for j in range(64):
-            assert selenium.run_js(f"return x[{i}][{j}] == 1")
-
-
-def test_typed_arrays(selenium):
-    selenium.load_package("numpy")
-    selenium.run("import numpy")
-    for jstype, npytype in (
-        ("Int8Array", "int8"),
-        ("Uint8Array", "uint8"),
-        ("Uint8ClampedArray", "uint8"),
-        ("Int16Array", "int16"),
-        ("Uint16Array", "uint16"),
-        ("Int32Array", "int32"),
-        ("Uint32Array", "uint32"),
-        ("Float32Array", "float32"),
-        ("Float64Array", "float64"),
-    ):
-        selenium.run_js(f"self.array = new {jstype}([1, 2, 3, 4]);\n")
-        assert selenium.run(
-            "from js import array\n"
-            "npyarray = numpy.asarray(array.to_py())\n"
-            f'npyarray.dtype.name == "{npytype}" '
-            "and npyarray == [1, 2, 3, 4]"
-        )
-
-
-@pytest.mark.skip_pyproxy_check
-@pytest.mark.parametrize("order", ("C", "F"))
-@pytest.mark.parametrize(
-    "dtype",
-    (
-        "int8",
-        "uint8",
-        "int16",
-        "uint16",
-        "int32",
-        "uint32",
-        "int64",
-        "uint64",
-        "float32",
-        "float64",
-    ),
-)
-def test_python2js_numpy_dtype(selenium, order, dtype):
-    selenium.load_package("numpy")
-    selenium.run("import numpy as np")
-
-    expected_result = [[[0, 1], [2, 3]], [[4, 5], [6, 7]]]
-
-    def assert_equal():
-        # We have to do this an element at a time, since the Selenium driver
-        # for Firefox does not convert TypedArrays to Python correctly
-        for i in range(2):
-            for j in range(2):
-                for k in range(2):
-                    assert (
-                        selenium.run_js(
-                            f"return Number(pyodide.globals.get('x').toJs()[{i}][{j}][{k}])"
-                        )
-                        == expected_result[i][j][k]
-                    )
-
-    selenium.run(
-        f"""
-        x = np.arange(8, dtype=np.{dtype})
-        x = x.reshape((2, 2, 2))
-        x = x.copy({order!r})
-        """
-    )
-    assert_equal()
-    classname = selenium.run_js(
-        "return pyodide.globals.get('x').toJs()[0][0].constructor.name"
-    )
-    # We expect a TypedArray subclass, such as Uint8Array, but not a plain-old
-    # Array
-    assert classname.endswith("Array")
-    assert classname != "Array"
-    selenium.run(
-        """
-        x = x.byteswap().newbyteorder()
-        """
-    )
-    assert_equal()
-    classname = selenium.run_js(
-        "return pyodide.globals.get('x').toJs()[0][0].constructor.name"
-    )
-    assert classname.endswith("Array")
-    assert classname != "Array"
-
-    assert selenium.run("np.array([True, False])") == [True, False]
-
-
-@pytest.mark.skip_pyproxy_check
-def test_py2js_buffer_clear_error_flag(selenium):
-    selenium.load_package("numpy")
-    selenium.run("import numpy as np")
-    selenium.run("x = np.array([['string1', 'string2'], ['string3', 'string4']])")
-    selenium.run_js(
-        """
-        pyodide.globals.get("x")
-        // Implicit assertion: this doesn't leave python error indicator set
-        // (automatically checked in conftest.py)
-        """
-    )
-
-
-@pytest.mark.skip_pyproxy_check
-@pytest.mark.parametrize(
-    "dtype",
-    (
-        "int8",
-        "uint8",
-        "int16",
-        "uint16",
-        "int32",
-        "uint32",
-        "int64",
-        "uint64",
-        "float32",
-        "float64",
-    ),
-)
-def test_python2js_numpy_scalar(selenium, dtype):
-    selenium.load_package("numpy")
-    selenium.run("import numpy as np")
-    selenium.run(
-        f"""
-        x = np.{dtype}(1)
-        """
-    )
-    assert (
-        selenium.run_js(
-            """
-            return pyodide.globals.get('x') == 1
-            """
-        )
-        is True
-    )
-    selenium.run(
-        """
-        x = x.byteswap().newbyteorder()
-        """
-    )
-    assert (
-        selenium.run_js(
-            """
-        return pyodide.globals.get('x') == 1
-        """
-        )
-        is True
-    )
-
-
-@pytest.mark.skip_pyproxy_check
-def test_runpythonasync_numpy(selenium_standalone):
-    selenium_standalone.run_async(
-        """
-        import numpy as np
-        x = np.zeros(5)
-        """
-    )
-    for i in range(5):
-        assert selenium_standalone.run_js(
-            f"return pyodide.globals.get('x').toJs()[{i}] == 0"
-        )
-
-
-@pytest.mark.xfail_browsers(
-    firefox="Timeout in WebWorker when using numpy in Firefox 87"
-)
-@pytest.mark.driver_timeout(30)
-def test_runwebworker_numpy(selenium_webworker_standalone):
-    output = selenium_webworker_standalone.run_webworker(
-        """
-        import numpy as np
-        x = np.zeros(5)
-        str(x)
-        """
-    )
-    assert output == "[0. 0. 0. 0. 0.]"
-
-
-@pytest.mark.skip_pyproxy_check
-def test_get_buffer(selenium):
-    selenium.run_js(
-        """
-        await pyodide.loadPackage(['numpy']);
-        pyodide.runPython(`
-            import numpy as np
-            x = np.arange(24)
-            z1 = x.reshape([8,3])
-            z2 = z1[-1::-1]
-            z3 = z1[::,-1::-1]
-            z4 = z1[-1::-1,-1::-1]
-        `);
-        for(let x of ["z1", "z2", "z3", "z4"]){
-            let z = pyodide.globals.get(x).getBuffer("u32");
-            for(let idx1 = 0; idx1 < 8; idx1++) {
-                for(let idx2 = 0; idx2 < 3; idx2++){
-                    let v1 = z.data[z.offset + z.strides[0] * idx1 + z.strides[1] * idx2];
-                    let v2 = pyodide.runPython(`repr(${x}[${idx1}, ${idx2}])`);
-                    console.log(`${v1}, ${typeof(v1)}, ${v2}, ${typeof(v2)}, ${v1===v2}`);
-                    if(v1.toString() !== v2){
-                        throw new Error(`Discrepancy ${x}[${idx1}, ${idx2}]: ${v1} != ${v2}`);
-                    }
-                }
-            }
-            z.release();
-        }
-        """
-    )
-
-
-@pytest.mark.skip_pyproxy_check
-@pytest.mark.parametrize(
-    "arg",
-    [
-        "np.arange(6).reshape((2, -1))",
-        "np.arange(12).reshape((3, -1))[::2, ::2]",
-        "np.arange(12).reshape((3, -1))[::-1, ::-1]",
-        "np.arange(12).reshape((3, -1))[::, ::-1]",
-        "np.arange(12).reshape((3, -1))[::-1, ::]",
-        "np.arange(12).reshape((3, -1))[::-2, ::-2]",
-        "np.arange(6).reshape((2, -1)).astype(np.int8, order='C')",
-        "np.arange(6).reshape((2, -1)).astype(np.int8, order='F')",
-        "np.arange(6).reshape((2, -1, 1))",
-        "np.ones((1, 1))[0:0]",  # shape[0] == 0
-        "np.ones(1)",  # ndim == 0
-    ]
-    + [
-        f"np.arange(3).astype(np.{type_})"
-        for type_ in ["int8", "uint8", "int16", "int32", "float32", "float64"]
-    ],
-)
-def test_get_buffer_roundtrip(selenium, arg):
-    selenium.run_js(
-        f"""
-        await pyodide.loadPackage(['numpy']);
-        pyodide.runPython(`
-            import numpy as np
-            x = {arg}
-        `);
-        self.x_js_buf = pyodide.globals.get("x").getBuffer();
-        x_js_buf.length = x_js_buf.data.length;
-        """
-    )
-
-    selenium.run_js(
-        """
-        pyodide.runPython(`
-            import itertools
-            from unittest import TestCase
-            from js import x_js_buf
-            assert_equal = TestCase().assertEqual
-
-            assert_equal(x_js_buf.ndim, x.ndim)
-            assert_equal(x_js_buf.shape.to_py(), list(x.shape))
-            assert_equal(x_js_buf.strides.to_py(), [s/x.itemsize for s in x.data.strides])
-            assert_equal(x_js_buf.format, x.data.format)
-            if len(x) == 0:
-                assert x_js_buf.length == 0
-            else:
-                minoffset = 1000
-                maxoffset = 0
-                for tup in itertools.product(*[range(n) for n in x.shape]):
-                    offset = x_js_buf.offset + sum(x*y for (x,y) in zip(tup, x_js_buf.strides))
-                    minoffset = min(offset, minoffset)
-                    maxoffset = max(offset, maxoffset)
-                    assert_equal(x[tup], x_js_buf.data[offset])
-                assert_equal(minoffset, 0)
-                assert_equal(maxoffset + 1, x_js_buf.length)
-            x_js_buf.release()
-        `);
-        """
-    )
-
-
-def test_get_buffer_big_endian(selenium):
-    selenium.run_js(
-        """
-        await pyodide.loadPackage(['numpy']);
-        self.a = pyodide.runPython(`
-            import numpy as np
-            np.arange(24, dtype="int16").byteswap().newbyteorder()
-        `);
-        """
-    )
-    with pytest.raises(
-        Exception, match="Javascript has no native support for big endian buffers"
-    ):
-        selenium.run_js("a.getBuffer()")
-    result = selenium.run_js(
-        """
-        let buf = a.getBuffer("i8")
-        let result = Array.from(buf.data);
-        buf.release();
-        a.destroy();
-        return result;
-        """
-    )
-    assert len(result) == 48
-    assert result[:18] == [0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8]
-
-
-def test_get_buffer_error_messages(selenium):
-    with pytest.raises(Exception, match="Javascript has no Float16 support"):
-        selenium.run_js(
-            """
-            await pyodide.loadPackage(['numpy']);
-            pyodide.runPython(`
-                import numpy as np
-                x = np.ones(2, dtype=np.float16)
-            `);
-            let x = pyodide.runPython("x");
-            try {
-                x.getBuffer();
-            } finally {
-                x.destroy();
-            }
-            """
-        )
-
-
-def test_fft(selenium):
-    selenium.run_js(
-        """
-        await pyodide.loadPackage(['numpy']);
-        pyodide.runPython(`
-            import numpy
-            assert all(numpy.fft.fft([1, 1]) == [2, 0])
-        `);
-        """
-    )
-
-
-@run_in_pyodide(packages=["numpy"])
-def test_np_unique(selenium):
-    """Numpy comparator functions formerly had a fatal error, see PR #2110"""
-    import numpy as np
-
-    np.unique(np.array([1.1, 1.1]), axis=-1)
diff --git a/integration_tests/recipes/scipy/cmdline_test_file.py b/integration_tests/recipes/scipy/cmdline_test_file.py
deleted file mode 100644
index 0d98ef20..00000000
--- a/integration_tests/recipes/scipy/cmdline_test_file.py
+++ /dev/null
@@ -1,8 +0,0 @@
-import numpy as np
-from scipy.sparse.linalg import svds
-
-rng = np.random.default_rng(0)
-A = rng.random((10, 10))
-
-res = svds(A, k=3, which="LM", random_state=0)
-print("res", res)
diff --git a/integration_tests/recipes/scipy/info.md b/integration_tests/recipes/scipy/info.md
deleted file mode 100644
index 97efdd05..00000000
--- a/integration_tests/recipes/scipy/info.md
+++ /dev/null
@@ -1,81 +0,0 @@
-The biggest issue that comes up in building scipy is that we don't have a good
-fortran to wasm compiler. Some version of flang classic might work.
-
-Instead of compiling from fortran directly, we rely on f2c to cross compile
-the code to C and then compile C to wasm. We rely on f2c both directly and via
-OpenBLAS which has f2c'd its Fortran files and then modified the generated C
-files by hand.
-
-A big problem with f2c is that it cannot handle implicit casts of function
-arguments, because it tries to guess the types of the arguments of the function
-being called based on the types of the arguments at the call site. There are
-two distinct versions of this:
-
-1. casts between number types -- we deal with this automatically in
-   `fix_inconsistent_decls` in `_f2c_fixes.py`
-2. casts between char\* and int -- this is too annoying to deal with
-   automatically, so we write manual patches.
-
-Type 1: the fortran equivalent of the following C code:
-
-```C
-double f(double x){
-  return x + 5;
-}
-
-double g(int x){
-  return f(x);
-}
-```
-
-gets f2c'd to
-
-```C
-double f(double x){
-  return x + 5;
-}
-
-double g(int x){
-  double f(int);
-  return f(x);
-}
-```
-
-When we try to compile this, we get an error saying that f has been declared
-with two different types.
-
-Type 2: For each string argument, the Fortran ABI adds arguments at the end of
-the argument list. LAPACK never declares functions as taking strings, preferring
-to call them integers:
-
-```C
-int some_lapack_func(int *some_string, int *some_string_length){
- // ...
-}
-```
-
-But then when we call it: `some_lapack_func("a string here", 14);` the f2c'd
-version looks like:
-
-```C
-int str_len = 14;
-int some_lapack_func(int *some_string, int *some_string_length, fortranlen some_string_length_again);
-some_lapack_func("a string here", &str_len, 14);
-```
-
-When changing `packages/scipy/meta.yaml`, rebuilding scipy takes time, it can
-be convenient to only build a few sub-packages to reduce iteration time. You
-can add something like this to `packages/scipy/meta.yaml`:
-
-```bash
-# Define which sub-packages to keep
-TO_KEEP='linalg|sparse|_lib|_build_utils'
-# Update scipy/setup.py
-perl -pi -e "s@(config.add_subpackage\(')(?!$TO_KEEP)@# \1\2@" scipy/setup.py
-# delete unwanted folders to avoid unneeded cythonization
-folders_to_delete=$(find scipy -mindepth 1 -maxdepth 1 -type d | grep -vP "$TO_KEEP")
-rm -rf $folders_to_delete
-```
-
-Building only `scipy.(linalg|sparse|_lib|_build_utils)` takes ~4 minutes on my
-machine compared to ~10-15 minutes for a full scipy build.
diff --git a/integration_tests/recipes/scipy/meta.yaml b/integration_tests/recipes/scipy/meta.yaml
deleted file mode 100644
index 6bff24da..00000000
--- a/integration_tests/recipes/scipy/meta.yaml
+++ /dev/null
@@ -1,204 +0,0 @@
-package:
-  name: scipy
-  version: 1.17.1
-  tag:
-    - min-scipy-stack
-    - cross-build
-  top-level:
-    - scipy
-
-# See extra explanation in info.md
-#
-# For future reference: if you see the following errors:
-#   Declaration error: adjustable dimension on non-argument
-# or:
-#   nonconstant array size
-# you are trying to compile code that isn't written to the fortran 77 standard.
-# The line number in the error points to the last line of the problematic
-# subroutine. Try deleting it.
-
-source:
-  url: https://files.pythonhosted.org/packages/source/s/scipy/scipy-1.17.1.tar.gz
-  sha256: 95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0
-
-  patches:
-    - patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
-    - patches/0002-gemm_-no-const.patch
-    - patches/0003-make-int-return-values.patch
-    - patches/0004-Fix-fitpack.patch
-    - patches/0005-Fix-gees-calls.patch
-    - patches/0006-Link-openblas-with-modules-that-require-f2c.patch
-    - patches/0007-Remove-chla_transtype.patch
-    - patches/0008-Set-wrapper-return-type-to-int.patch
-    - patches/0010-Explicitly-convert-return-value-of-SUPERLU_MALLOC.patch
-    - patches/0011-MAINT-linalg-Remove-dummy-argument-from-larf-wrapper.patch # drop after scipy 1.18
-build:
-  vendor-sharedlib: true
-  # NumPy 2.1 disabled visibility for symbols outside of extension modules
-  # by default, so this breaks SciPy tests from modules that use f2py to
-  # build because they rely on the visibility of symbols in NumPy. This flag
-  # is currently used as a stop-gap measure. For more information, please see
-  # 1. https://github.com/numpy/numpy/pull/26286, and
-  # 2. https://github.com/numpy/numpy/pull/26103.
-  cflags: |
-    -DNPY_API_SYMBOL_ATTRIBUTE=__attribute__((visibility("default")))
-    -I$(WASM_LIBRARY_DIR)/include
-    -Wno-return-type
-    -DUNDERSCORE_G77
-    -fvisibility=default
-  cxxflags: |
-    -fwasm-exceptions
-    -fvisibility=default
-  ldflags: |
-    -L$(NUMPY_LIB)/core/lib/
-    -L$(NUMPY_LIB)/random/lib/
-    -fwasm-exceptions
-
-  # Exclude tests via Meson's install tags functionality.
-  # unvendor-tests is automatically set to false by the CI SciPy trigger, so
-  # that when we want to test SciPy, we retain the tests inside the wheel
-  unvendor-tests: true
-  # install-args=--tags=runtime,python-runtime,devel
-  # Disable when running tests, enable when a PR is ready, i.e., building for distribution.
-  backend-flags: |
-    build-dir=build
-
-  # IMPORTANT: Other locations important in scipy build process:
-  # There are two files built in the "capture" pass that need patching:
-  #    _blas_subroutines.h, and _cython
-  # Scipy has a bunch of custom logic implemented in
-  # pyodide-build/pyodide_build/_f2c_fixes.py.
-  script: |
-    set -x
-    git clone https://github.com/hoodmane/f2c.git --depth 1
-    (cd f2c/src && cp makefile.u makefile && sed -i "s/gram.c:/gram.c1:/" makefile && make)
-    export F2C_PATH=$(pwd)/f2c/src/f2c
-
-    echo F2C_PATH: $F2C_PATH
-    export NPY_BLAS_LIBS="-I$WASM_LIBRARY_DIR/include $WASM_LIBRARY_DIR/lib/libopenblas.so"
-    export NPY_LAPACK_LIBS="-I$WASM_LIBRARY_DIR/include $WASM_LIBRARY_DIR/lib/libopenblas.so"
-
-    sed -i 's/void DQA/int DQA/g' scipy/integrate/__quadpack.h
-
-    # Change many functions that return void into functions that return int
-    find scipy -name "*.c*" -type f | xargs sed -i 's/extern void F_FUNC/extern int F_FUNC/g'
-
-    sed -i 's/void F_FUNC/int F_FUNC/g' scipy/odr/__odrpack.c
-    sed -i 's/^void/int/g' scipy/odr/odrpack.h
-    sed -i 's/^void/int/g' scipy/odr/__odrpack.c
-
-    sed -i 's/void BLAS_FUNC/int BLAS_FUNC/g' scipy/special/lapack_defs.h
-    # sed -i 's/void F_FUNC/int F_FUNC/g' scipy/linalg/_lapack_subroutines.h
-    sed -i 's/extern void/extern int/g' scipy/optimize/__minpack.h
-    sed -i 's/void/int/g' scipy/linalg/cython_blas_signatures.txt
-    sed -i 's/void/int/g' scipy/linalg/cython_lapack_signatures.txt
-    sed -i 's/^void BLAS_FUNC/int BLAS_FUNC/g' scipy/linalg/src/_common_array_utils.hh
-
-    # Change fortran functions called in C code to return int instead of void
-    # This adhoc regex checks function names ending with _ such as `void zgetrs_(`
-    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/linalg/_common_array_utils.h
-    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/linalg/_matfuncs_expm.h
-    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/sparse/linalg/_propack/PROPACK/src/include/blaslapack_declarations.h
-    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/sparse/linalg/_eigen/arpack/arnaud/src/blaslapack_declarations.h
-    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/integrate/src/blaslapack_declarations.h
-    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/optimize/__lbfgsb.h
-    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/optimize/__nnls.h
-    sed -i 's/^void \([a-z0-9]*_\)(/int \1(/g' scipy/optimize/__slsqp.h
-
-    sed -i 's/^void/int/g' scipy/interpolate/src/_fitpackmodule.c
-    sed -i 's/void BLAS_FUNC/int BLAS_FUNC/g' scipy/interpolate/src/__fitpack.h
-
-    sed -i 's/extern void/extern int/g' scipy/sparse/linalg/_dsolve/SuperLU/SRC/*.{c,h}
-    sed -i 's/PUBLIC void/PUBLIC int/g' scipy/sparse/linalg/_dsolve/SuperLU/SRC/*.{c,h}
-    sed -i 's/^void/int/g' scipy/sparse/linalg/_dsolve/SuperLU/SRC/*.{c,h}
-    sed -i 's/^void/int/g' scipy/sparse/linalg/_dsolve/*.{c,h}
-    sed -i 's/void \(.\)print/int \1/g' scipy/sparse/linalg/_dsolve/SuperLU/SRC/*.{c,h}
-    sed -i 's/TYPE_GENERIC_FUNC(\(.*\), void)/TYPE_GENERIC_FUNC(\1, int)/g' scipy/sparse/linalg/_dsolve/_superluobject.h
-
-    sed -i 's/^void/int/g' scipy/optimize/_trlib/trlib_private.h
-    sed -i 's/^void/int/g' scipy/optimize/_trlib/trlib/trlib_private.h
-    sed -i 's/^void/int/g' scipy/_build_utils/src/wrap_dummy_g77_abi.c
-    sed -i 's/, int)/)/g' scipy/optimize/_trlib/trlib_private.h
-    sed -i 's/, 1)/)/g' scipy/optimize/_trlib/trlib_private.h
-
-    sed -i 's/^void/int/g' scipy/spatial/qhull_misc.h
-    sed -i 's/, size_t)/)/g' scipy/spatial/qhull_misc.h
-    sed -i 's/,1)/)/g' scipy/spatial/qhull_misc.h
-
-    # Input error causes "duplicate symbol" linker errors. Empty out the file.
-    echo "" > scipy/sparse/linalg/_dsolve/SuperLU/SRC/input_error.c
-
-    # https://github.com/mesonbuild/meson/blob/e542901af6e30865715d3c3c18f703910a096ec0/mesonbuild/backend/ninjabackend.py#L94
-    # Prevent from using response file. The response file that meson generates is not compatible to pyodide-build
-    export MESON_RSP_THRESHOLD=131072
-
-  _retain-test-patterns:
-    - "*_page_trend_test.py"
-    - "*bws_test.py"
-
-  cross-build-env: true
-  cross-build-files:
-    - scipy/linalg/cython_lapack.pxd
-    - scipy/linalg/cython_blas.pxd
-
-requirements:
-  host:
-    - numpy
-    - libopenblas
-    - libboost
-  run:
-    - numpy
-  executable:
-    - gfortran
-  constraint:
-    # Getting: Error: Dynamic linking error: cannot resolve symbol pow_di
-    - meson < 1.10
-test:
-  imports:
-    - scipy
-    - scipy.cluster
-    - scipy.cluster.vq
-    - scipy.cluster.hierarchy
-    - scipy.constants
-    - scipy.fft
-    - scipy.fftpack
-    - scipy.integrate
-    - scipy.interpolate
-    - scipy.io
-    - scipy.io.arff
-    - scipy.io.matlab
-    - scipy.io.wavfile
-    - scipy.linalg
-    - scipy.linalg.blas
-    - scipy.linalg.cython_blas
-    - scipy.linalg.lapack
-    - scipy.linalg.cython_lapack
-    - scipy.linalg.interpolative
-    - scipy.misc
-    - scipy.ndimage
-    - scipy.odr
-    - scipy.optimize
-    - scipy.signal
-    - scipy.signal.windows
-    - scipy.sparse
-    - scipy.sparse.linalg
-    - scipy.sparse.csgraph
-    - scipy.spatial
-    - scipy.spatial.distance
-    - scipy.spatial.transform
-    - scipy.special
-    - scipy.stats
-    - scipy.stats.contingency
-    - scipy.stats.distributions
-    - scipy.stats.mstats
-    - scipy.stats.qmc
-about:
-  home: https://www.scipy.org
-  PyPI: https://pypi.org/project/scipy
-  summary: "SciPy: Scientific Library for Python"
-  license: BSD-3-Clause
-extra:
-  recipe-maintainers:
-    - lesteve
-    - steppi
-    - agriyakhetarpal
diff --git a/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch b/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
deleted file mode 100644
index c046c534..00000000
--- a/integration_tests/recipes/scipy/patches/0001-Fix-dstevr-in-special-lapack_defs.h.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-From 45a31145679c83f2719b6420f234d484b9459697 Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Fri, 18 Mar 2022 16:25:39 -0700
-Subject: [PATCH 01/11] Fix dstevr in special/lapack_defs.h
-
----
- scipy/special/lapack_defs.h | 5 ++---
- 1 file changed, 2 insertions(+), 3 deletions(-)
-
-diff --git a/scipy/special/lapack_defs.h b/scipy/special/lapack_defs.h
-index 0d20ba1ca..d4325f71f 100644
---- a/scipy/special/lapack_defs.h
-+++ b/scipy/special/lapack_defs.h
-@@ -8,13 +8,12 @@ extern void BLAS_FUNC(dstevr)(char *jobz, char *range, CBLAS_INT *n, double *d,
-                               double *vl, double *vu, CBLAS_INT *il, CBLAS_INT *iu, double *abstol,
-                               CBLAS_INT *m, double *w, double *z, CBLAS_INT *ldz, CBLAS_INT *isuppz,
-                               double *work, CBLAS_INT *lwork, CBLAS_INT *iwork, CBLAS_INT *liwork,
--                              CBLAS_INT *info, size_t jobz_len, size_t range_len);
-+                              CBLAS_INT *info);
- 
- static void c_dstevr(char *jobz, char *range, CBLAS_INT *n, double *d, double *e,
-                      double *vl, double *vu, CBLAS_INT *il, CBLAS_INT *iu, double *abstol,
-                      CBLAS_INT *m, double *w, double *z, CBLAS_INT *ldz, CBLAS_INT *isuppz,
-                      double *work, CBLAS_INT *lwork, CBLAS_INT *iwork, CBLAS_INT *liwork, CBLAS_INT *info) {
-     BLAS_FUNC(dstevr)(jobz, range, n, d, e, vl, vu, il, iu, abstol, m,
--                      w, z, ldz, isuppz, work, lwork, iwork, liwork, info,
--                      1, 1);
-+                      w, z, ldz, isuppz, work, lwork, iwork, liwork, info);
- }
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0002-gemm_-no-const.patch b/integration_tests/recipes/scipy/patches/0002-gemm_-no-const.patch
deleted file mode 100644
index e8e1db46..00000000
--- a/integration_tests/recipes/scipy/patches/0002-gemm_-no-const.patch
+++ /dev/null
@@ -1,86 +0,0 @@
-From e528227dd37c8b0512381992c222789a114e3169 Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Sat, 18 Dec 2021 11:41:15 -0800
-Subject: [PATCH 02/11] gemm_ no const
-
-cgemm, dgemm, sgemm, and zgemm are declared with `const` in slu_cdefs.h, but
-other places don't have the cosnt causing compile errors.
-This patch drops the consts and fixes the problem.
----
- scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h | 6 +++---
- scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h | 6 +++---
- scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h | 6 +++---
- scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h | 6 +++---
- 4 files changed, 12 insertions(+), 12 deletions(-)
-
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h
-index dfc0516ac..92d7d7d6b 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_cdefs.h
-@@ -262,9 +262,9 @@ extern void    ccheck_tempv(int, singlecomplex *);
- 
- /*! \brief BLAS */
- 
--extern int cgemm_(const char*, const char*, const int*, const int*, const int*,
--                  const singlecomplex*, const singlecomplex*, const int*, const singlecomplex*,
--		  const int*, const singlecomplex*, singlecomplex*, const int*);
-+extern int cgemm_( char*,  char*,  int*,  int*,  int*,
-+                   singlecomplex*,  singlecomplex*,  int*,  singlecomplex*,
-+		   int*,  singlecomplex*, singlecomplex*,  int*);
- extern int ctrsv_(char*, char*, char*, int*, singlecomplex*, int*,
-                   singlecomplex*, int*);
- extern int ctrsm_(char*, char*, char*, char*, int*, int*,
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h
-index 3b5aa509f..1305641bd 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_ddefs.h
-@@ -260,9 +260,9 @@ extern void    dcheck_tempv(int, double *);
- 
- /*! \brief BLAS */
- 
--extern int dgemm_(const char*, const char*, const int*, const int*, const int*,
--                  const double*, const double*, const int*, const double*,
--		  const int*, const double*, double*, const int*);
-+extern int dgemm_( char*,  char*,  int*,  int*,  int*,
-+                   double*,  double*,  int*,  double*,
-+		   int*,  double*, double*,  int*);
- extern int dtrsv_(char*, char*, char*, int*, double*, int*,
-                   double*, int*);
- extern int dtrsm_(char*, char*, char*, char*, int*, int*,
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h
-index 9bb6a38e7..b013962a4 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_sdefs.h
-@@ -259,9 +259,9 @@ extern void    scheck_tempv(int, float *);
- 
- /*! \brief BLAS */
- 
--extern int sgemm_(const char*, const char*, const int*, const int*, const int*,
--                  const float*, const float*, const int*, const float*,
--		  const int*, const float*, float*, const int*);
-+extern int sgemm_( char*,  char*,  int*,  int*,  int*,
-+                   float*,  float*,  int*,  float*,
-+		   int*,  float*, float*,  int*);
- extern int strsv_(char*, char*, char*, int*, float*, int*,
-                   float*, int*);
- extern int strsm_(char*, char*, char*, char*, int*, int*,
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h
-index c6418d584..c5a2692be 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_zdefs.h
-@@ -262,9 +262,9 @@ extern void    zcheck_tempv(int, doublecomplex *);
- 
- /*! \brief BLAS */
- 
--extern int zgemm_(const char*, const char*, const int*, const int*, const int*,
--                  const doublecomplex*, const doublecomplex*, const int*, const doublecomplex*,
--		  const int*, const doublecomplex*, doublecomplex*, const int*);
-+extern int zgemm_( char*,  char*,  int*,  int*,  int*,
-+                   doublecomplex*,  doublecomplex*,  int*,  doublecomplex*,
-+		   int*,  doublecomplex*, doublecomplex*,  int*);
- extern int ztrsv_(char*, char*, char*, int*, doublecomplex*, int*,
-                   doublecomplex*, int*);
- extern int ztrsm_(char*, char*, char*, char*, int*, int*,
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0003-make-int-return-values.patch b/integration_tests/recipes/scipy/patches/0003-make-int-return-values.patch
deleted file mode 100644
index 65b0d089..00000000
--- a/integration_tests/recipes/scipy/patches/0003-make-int-return-values.patch
+++ /dev/null
@@ -1,245 +0,0 @@
-From a86a2304fd925f815bbb0e0753e46a7b863e2de2 Mon Sep 17 00:00:00 2001
-From: Joe Marshall 
-Date: Wed, 6 Apr 2022 21:25:13 -0700
-Subject: [PATCH 03/11] make int return values
-
-The return values of f2c functions are insignificant in most cases, so often it
-is treated as returning void, when it really should return int (values are
-"returned" by writing to pointers passed as an argument, but an obscure feature
-known as alternative returns can cause the return value to be significant).
-
-There's a big change to scipy/linalg/_cython_wrapper_generators.py, which is
-called on build to generate python wrappers for lapack and BLAS. The change
-makes everything call direct to CLAPACK with the correct function signatures
-and also fixes some fortran -> c linking oddities that occur because f2py assumes
-different function signatures to f2c, which in turn creates different function
-signatures compared to what has been done in CLAPACK.
-
-f2py is patched in numpy to make subroutines return int.
-
-emscripten is very strict about void vs int returns and function signatures, so
-we change everything to return int from subroutines, and signatures are altered
-to be consistent.
-
-Co-Developed-by: Joe Marshall 
-Co-Authored-By: Joe Marshall 
----
- scipy/_build_utils/src/wrap_g77_abi.c         | 16 ++++++------
- scipy/integrate/_odepackmodule.c              |  8 +++---
- scipy/odr/__odrpack.c                         |  2 +-
- .../_dsolve/SuperLU/SRC/ilu_cdrop_row.c       |  8 +++---
- .../_dsolve/SuperLU/SRC/ilu_scopy_to_ucol.c   |  2 +-
- .../_dsolve/SuperLU/SRC/scipy_slu_config.h    |  3 +++
- .../linalg/_dsolve/SuperLU/SRC/sgssvx.c       |  7 ++---
- .../linalg/_dsolve/SuperLU/SRC/slu_dcomplex.h |  5 +++-
- .../linalg/_dsolve/SuperLU/SRC/slu_scomplex.h |  5 ++--
- scipy/sparse/linalg/_dsolve/_superlu_utils.c  |  4 +--
- .../linalg/_eigen/arpack/ARPACK/SRC/debug.h   | 20 +++++++-------
- .../linalg/_eigen/arpack/ARPACK/SRC/stat.h    | 26 +++++++++----------
- 12 files changed, 57 insertions(+), 49 deletions(-)
-
-diff --git a/scipy/_build_utils/src/wrap_g77_abi.c b/scipy/_build_utils/src/wrap_g77_abi.c
-index f35c94f984..1872d335aa 100644
---- a/scipy/_build_utils/src/wrap_g77_abi.c
-+++ b/scipy/_build_utils/src/wrap_g77_abi.c
-@@ -71,7 +71,7 @@ double_complex F_FUNC(wzdotu,WZDOTU)(CBLAS_INT *n, double_complex *zx, \
-     return ret;
- }
- 
--void BLAS_FUNC(sladiv)(float *xr, float *xi, float *yr, float *yi, \
-+int BLAS_FUNC(sladiv)(float *xr, float *xi, float *yr, float *yi, \
-     float *retr, float *reti);
- float_complex F_FUNC(wcladiv,WCLADIV)(float_complex *x, float_complex *y){
-     float_complex ret;
-@@ -83,7 +83,7 @@ float_complex F_FUNC(wcladiv,WCLADIV)(float_complex *x, float_complex *y){
-     return ret;
- }
- 
--void BLAS_FUNC(dladiv)(double *xr, double *xi, double *yr, double *yi, \
-+int BLAS_FUNC(dladiv)(double *xr, double *xi, double *yr, double *yi, \
-     double *retr, double *reti);
- double_complex F_FUNC(wzladiv,WZLADIV)(double_complex *x, double_complex *y){
-     double_complex ret;
-@@ -95,31 +95,31 @@ double_complex F_FUNC(wzladiv,WZLADIV)(double_complex *x, double_complex *y){
-     return ret;
- }
- 
--void F_FUNC(cdotcwrp,WCDOTCWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
-+int F_FUNC(cdotcwrp,WCDOTCWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
-         CBLAS_INT *incx, float_complex *cy, CBLAS_INT *incy){
-     *ret = F_FUNC(wcdotc,WCDOTC)(n, cx, incx, cy, incy);
- }
- 
--void F_FUNC(zdotcwrp,WZDOTCWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
-+int F_FUNC(zdotcwrp,WZDOTCWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
-         CBLAS_INT *incx, double_complex *zy, CBLAS_INT *incy){
-     *ret = F_FUNC(wzdotc,WZDOTC)(n, zx, incx, zy, incy);
- }
- 
--void F_FUNC(cdotuwrp,CDOTUWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
-+int F_FUNC(cdotuwrp,CDOTUWRP)(float_complex *ret, CBLAS_INT *n, float_complex *cx, \
-         CBLAS_INT *incx, float_complex *cy, CBLAS_INT *incy){
-     *ret = F_FUNC(wcdotu,WCDOTU)(n, cx, incx, cy, incy);
- }
- 
--void F_FUNC(zdotuwrp,ZDOTUWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
-+int F_FUNC(zdotuwrp,ZDOTUWRP)(double_complex *ret, CBLAS_INT *n, double_complex *zx, \
-         CBLAS_INT *incx, double_complex *zy, CBLAS_INT *incy){
-     *ret = F_FUNC(wzdotu,WZDOTU)(n, zx, incx, zy, incy);
- }
- 
--void F_FUNC(cladivwrp,CLADIVWRP)(float_complex *ret, float_complex *x, float_complex *y){
-+int F_FUNC(cladivwrp,CLADIVWRP)(float_complex *ret, float_complex *x, float_complex *y){
-     *ret = F_FUNC(wcladiv,WCLADIV)(x, y);
- }
- 
--void F_FUNC(zladivwrp,ZLADIVWRP)(double_complex *ret, double_complex *x, double_complex *y){
-+int F_FUNC(zladivwrp,ZLADIVWRP)(double_complex *ret, double_complex *x, double_complex *y){
-     *ret = F_FUNC(wzladiv,WZLADIV)(x, y);
- }
- 
-diff --git a/scipy/odr/__odrpack.c b/scipy/odr/__odrpack.c
-index c806e33fbf..c4b822eb92 100644
---- a/scipy/odr/__odrpack.c
-+++ b/scipy/odr/__odrpack.c
-@@ -13,7 +13,7 @@
- #include "odrpack.h"
- 
- 
--void F_FUNC(dodrc,DODRC)(void (*fcn)(F_INT *n, F_INT *m, F_INT *np, F_INT *nq, F_INT *ldn, F_INT *ldm,
-+void F_FUNC(dodrc,DODRC)(int (*fcn)(F_INT *n, F_INT *m, F_INT *np, F_INT *nq, F_INT *ldn, F_INT *ldm,
-             F_INT *ldnp, double *beta, double *xplusd, F_INT *ifixb, F_INT *ifixx,
-             F_INT *ldifx, F_INT *ideval, double *f, double *fjacb, double *fjacd,
-             F_INT *istop),
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_cdrop_row.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_cdrop_row.c
-index c1dc7fcf8f..d1903db4a6 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_cdrop_row.c
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_cdrop_row.c
-@@ -23,10 +23,10 @@ at the top-level directory.
- #include 
- #include "slu_cdefs.h"
- 
--extern void cswap_(int *, singlecomplex [], int *, singlecomplex [], int *);
--extern void caxpy_(int *, singlecomplex *, singlecomplex [], int *, singlecomplex [], int *);
--extern void ccopy_(int *, singlecomplex [], int *, singlecomplex [], int *);
--extern void scopy_(int *, float [], int *, float [], int *);
-+extern int cswap_(int *, singlecomplex [], int *, singlecomplex [], int *);
-+extern int caxpy_(int *, singlecomplex *, singlecomplex [], int *, singlecomplex [], int *);
-+extern int ccopy_(int *, singlecomplex [], int *, singlecomplex [], int *);
-+extern int scopy_(int *, float [], int *, float [], int *);
- extern float scasum_(int *, singlecomplex *, int *);
- extern float scnrm2_(int *, singlecomplex *, int *);
- extern double dnrm2_(int *, double [], int *);
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_scopy_to_ucol.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_scopy_to_ucol.c
-index 4e2654e8ac..d5b955d40e 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_scopy_to_ucol.c
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/ilu_scopy_to_ucol.c
-@@ -26,7 +26,7 @@ at the top-level directory.
- int num_drop_U;
- #endif
- 
--extern void scopy_(int *, float [], int *, float [], int *);
-+extern int scopy_(int *, float [], int *, float [], int *);
- 
- #if 0
- static float *A;  /* used in _compare_ only */
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h
-index 5afc93b5d9..7ac5f80fb9 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/scipy_slu_config.h
-@@ -3,6 +3,9 @@
- 
- #include 
- 
-+#undef complex
-+#include "f2c.h"
-+#define complex singlecomplex
- /*
-  * Support routines
-  */
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgssvx.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgssvx.c
-index 1395752d4c..7f5538140d 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgssvx.c
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgssvx.c
-@@ -21,6 +21,8 @@ at the top-level directory.
-  */
- #include "slu_sdefs.h"
- 
-+extern float slangs(char *, SuperMatrix *);
-+
- /*! \brief
-  *
-  * 
-@@ -377,8 +379,6 @@ sgssvx(superlu_options_t *options, SuperMatrix *A, int *perm_c, int *perm_r,
-     double    t0;      /* temporary time */
-     double    *utime;
- 
--    /* External functions */
--    extern float slangs(char *, SuperMatrix *);
- 
-     Bstore = B->Store;
-     Xstore = X->Store;
-@@ -573,7 +573,8 @@ printf("dgssvx: Fact=%4d, Trans=%4d, equed=%c\n",
-         } else {
- 	    *(unsigned char *)norm = 'I';
-         }
--        anorm = slangs(norm, AA);
-+        anorm = slangs(norm, AA);    /* External functions */
-+        extern float slangs(char *, SuperMatrix *);
-         sgscon(norm, L, U, anorm, rcond, stat, &info1);
-         utime[RCOND] = SuperLU_timer_() - t0;
-     }
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_dcomplex.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_dcomplex.h
-index 67e83bcc77..e5757d5c4d 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_dcomplex.h
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_dcomplex.h
-@@ -28,7 +28,10 @@ at the top-level directory.
- #ifndef DCOMPLEX_INCLUDE
- #define DCOMPLEX_INCLUDE
- 
--typedef struct { double r, i; } doublecomplex;
-+#include"scipy_slu_config.h"
-+
-+// defined in clapack
-+//typedef struct { double r, i; } doublecomplex;
- 
- 
- /* Macro definitions */
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
-index 83be8c971f..047a07ce9c 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/slu_scomplex.h
-@@ -27,8 +27,9 @@ at the top-level directory.
- 
- #ifndef SCOMPLEX_INCLUDE
- #define SCOMPLEX_INCLUDE
--
--typedef struct { float r, i; } singlecomplex;
-+#include"scipy_slu_config.h"
-+// defined in  CLAPACK
-+//typedef struct { float r, i; } singlecomplex;
- 
- 
- /* Macro definitions */
-diff --git a/scipy/sparse/linalg/_dsolve/_superlu_utils.c b/scipy/sparse/linalg/_dsolve/_superlu_utils.c
-index 49b928a431..0822687719 100644
---- a/scipy/sparse/linalg/_dsolve/_superlu_utils.c
-+++ b/scipy/sparse/linalg/_dsolve/_superlu_utils.c
-@@ -243,12 +243,12 @@ int input_error(char *srname, int *info)
-  * Stubs for Harwell Subroutine Library functions that SuperLU tries to call.
-  */
- 
--void mc64id_(int *a)
-+int mc64id_(int *a)
- {
-     superlu_python_module_abort("chosen functionality not available");
- }
- 
--void mc64ad_(int *a, int *b, int *c, int d[], int e[], double f[],
-+int mc64ad_(int *a, int *b, int *c, int d[], int e[], double f[],
- 	     int *g, int h[], int *i, int j[], int *k, double l[],
- 	     int m[], int n[])
- {
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0004-Fix-fitpack.patch b/integration_tests/recipes/scipy/patches/0004-Fix-fitpack.patch
deleted file mode 100644
index c67bd265..00000000
--- a/integration_tests/recipes/scipy/patches/0004-Fix-fitpack.patch
+++ /dev/null
@@ -1,112 +0,0 @@
-From c784d3a1ee38da88943364de4ea847a3b9cd155f Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Tue, 30 Aug 2022 11:51:53 -0700
-Subject: [PATCH 04/11] Fix fitpack
-
----
- scipy/interpolate/fitpack/dblint.f | 9 ++++-----
- scipy/interpolate/fitpack/evapol.f | 5 ++---
- scipy/interpolate/fitpack/fprati.f | 5 ++---
- scipy/interpolate/fitpack/splint.f | 7 +++----
- 4 files changed, 11 insertions(+), 15 deletions(-)
-
-diff --git a/scipy/interpolate/fitpack/dblint.f b/scipy/interpolate/fitpack/dblint.f
-index 8ae6b175f..51ec84744 100644
---- a/scipy/interpolate/fitpack/dblint.f
-+++ b/scipy/interpolate/fitpack/dblint.f
-@@ -1,7 +1,6 @@
--      recursive function dblint(tx,nx,ty,ny,c,kx,ky,xb,xe,yb,
--     *    ye,wrk) result(dblint_res)
-+      recursive real*8 function dblint(tx,nx,ty,ny,c,kx,ky,xb,xe,yb,
-+     *    ye,wrk)
-       implicit none
--      real*8 :: dblint_res
- c  function dblint calculates the double integral
- c         / xe  / ye
- c        |     |      s(x,y) dx dy
-@@ -75,7 +74,7 @@ c  we calculate the integrals of the normalized b-splines ni,kx+1(x)
- c  we calculate the integrals of the normalized b-splines nj,ky+1(y)
-       call fpintb(ty,ny,wrk(nkx1+1),nky1,yb,ye)
- c  calculate the integral of s(x,y)
--      dblint_res = 0.
-+      dblint = 0.
-       do 200 i=1,nkx1
-         res = wrk(i)
-         if(res.eq.0.) go to 200
-@@ -84,7 +83,7 @@ c  calculate the integral of s(x,y)
-         do 100 j=1,nky1
-           m = m+1
-           l = l+1
--          dblint_res = dblint_res + res*wrk(l)*c(m)
-+          dblint = dblint + res*wrk(l)*c(m)
-  100    continue
-  200  continue
-       return
-diff --git a/scipy/interpolate/fitpack/evapol.f b/scipy/interpolate/fitpack/evapol.f
-index f02569a40..1e4d65724 100644
---- a/scipy/interpolate/fitpack/evapol.f
-+++ b/scipy/interpolate/fitpack/evapol.f
-@@ -1,6 +1,5 @@
--      recursive function evapol(tu,nu,tv,nv,c,rad,x,y) result(e_res)
-+      recursive real*8 function evapol(tu,nu,tv,nv,c,rad,x,y)
-       implicit none
--      real*8 :: e_res
- c  function program evacir evaluates the function f(x,y) = s(u,v),
- c  defined through the transformation
- c      x = u*rad(v)*cos(v)    y = u*rad(v)*sin(v)
-@@ -78,7 +77,7 @@ c  calculate the (u,v)-coordinates of the given point.
-       if(u.gt.one) u = one
- c  evaluate s(u,v)
-   10  call bispev(tu,nu,tv,nv,c,3,3,u,1,v,1,f,wrk,8,iwrk,2,ier)
--      e_res = f
-+      evapol = f
-       return
-       end
- 
-diff --git a/scipy/interpolate/fitpack/fprati.f b/scipy/interpolate/fitpack/fprati.f
-index 71c57eb01..97b5851df 100644
---- a/scipy/interpolate/fitpack/fprati.f
-+++ b/scipy/interpolate/fitpack/fprati.f
-@@ -1,6 +1,5 @@
--      recursive function fprati(p1,f1,p2,f2,p3,f3) result(fprati_res)
-+      real*8 function fprati(p1,f1,p2,f2,p3,f3)
-       implicit none
--      real*8 :: fprati_res
- c  given three points (p1,f1),(p2,f2) and (p3,f3), function fprati
- c  gives the value of p such that the rational interpolating function
- c  of the form r(p) = (u*p+v)/(p+w) equals zero at p.
-@@ -26,6 +25,6 @@ c  adjust the value of p1,f1,p3 and f3 such that f1 > 0 and f3 < 0.
-       go to 40
-   30  p3 = p2
-       f3 = f2
--  40  fprati_res = p
-+  40  fprati = p
-       return
-       end
-diff --git a/scipy/interpolate/fitpack/splint.f b/scipy/interpolate/fitpack/splint.f
-index 02b00da6a..6024a0476 100644
---- a/scipy/interpolate/fitpack/splint.f
-+++ b/scipy/interpolate/fitpack/splint.f
-@@ -1,6 +1,5 @@
--      recursive function splint(t,n,c,nc,k,a,b,wrk) result(splint_res)
-+      real*8 function splint(t,n,c,nc,k,a,b,wrk)
-       implicit none
--      real*8 :: splint_res
- c  function splint calculates the integral of a spline function s(x)
- c  of degree k, which is given in its normalized b-spline representation
- c
-@@ -54,9 +53,9 @@ c  calculate the integrals wrk(i) of the normalized b-splines
- c  ni,k+1(x), i=1,2,...nk1.
-       call fpintb(t,n,wrk,nk1,a,b)
- c  calculate the integral of s(x).
--      splint_res = 0.0d0
-+      splint = 0.0d0
-       do 10 i=1,nk1
--        splint_res = splint_res+c(i)*wrk(i)
-+        splint = splint+c(i)*wrk(i)
-   10  continue
-       return
-       end
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0005-Fix-gees-calls.patch b/integration_tests/recipes/scipy/patches/0005-Fix-gees-calls.patch
deleted file mode 100644
index 1bf0b0ca..00000000
--- a/integration_tests/recipes/scipy/patches/0005-Fix-gees-calls.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 8addc1da35bc63df651946ef14c723797a431e0c Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Mon, 26 Jun 2023 20:12:25 -0700
-Subject: [PATCH 05/11] Fix gees calls
-
----
- scipy/linalg/flapack_gen.pyf.src | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/scipy/linalg/flapack_gen.pyf.src b/scipy/linalg/flapack_gen.pyf.src
-index 04037fdca..3686cea86 100644
---- a/scipy/linalg/flapack_gen.pyf.src
-+++ b/scipy/linalg/flapack_gen.pyf.src
-@@ -1196,8 +1196,8 @@ subroutine gees(compute_v,sort_t,select,n,a,nrows,sdim,w,vs,
-     !  A = Z * T * Z^H  -- a complex matrix is in Schur form if it is upper
-     !  triangular
- 
--    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,w,vs,&ldvs,work,&lwork,rwork,bwork,&info,1,1)
--    callprotoargument char*,char*,F_INT(*)(*),F_INT*,*,F_INT*,F_INT*,*,*,F_INT*,*,F_INT*,*,F_INT*,F_INT*,F_INT,F_INT
-+    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,w,vs,&ldvs,work,&lwork,rwork,bwork,&info)
-+    callprotoargument char*,char*,F_INT(*)(*),F_INT*,*,F_INT*,F_INT*,*,*,F_INT*,*,F_INT*,*,F_INT*,F_INT*
- 
-     use gees__user__routines
- 
-@@ -1226,8 +1226,8 @@ subroutine gees(compute_v,sort_t,select,n,a,nrows,sdim,wr,wi,v
-     !  A = Z * T * Z^H  -- a real matrix is in Schur form if it is upper quasi-
-     !  triangular with 1x1 and 2x2 blocks.
- 
--    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,wr,wi,vs,&ldvs,work,&lwork,bwork,&info,1,1)
--    callprotoargument char*,char*,F_INT(*)(*,*),F_INT*,*,F_INT*,F_INT*,*,*,*,F_INT*,*,F_INT*,F_INT*,F_INT*,F_INT,F_INT
-+    callstatement (*f2py_func)((compute_v?"V":"N"),(sort_t?"S":"N"),cb_select_in_gees__user__routines,&n,a,&nrows,&sdim,wr,wi,vs,&ldvs,work,&lwork,bwork,&info)
-+    callprotoargument char*,char*,F_INT(*)(*,*),F_INT*,*,F_INT*,F_INT*,*,*,*,F_INT*,*,F_INT*,F_INT*,F_INT*
- 
-     use gees__user__routines
- 
--- 
-2.34.1
-
diff --git a/integration_tests/recipes/scipy/patches/0006-Link-openblas-with-modules-that-require-f2c.patch b/integration_tests/recipes/scipy/patches/0006-Link-openblas-with-modules-that-require-f2c.patch
deleted file mode 100644
index b8a0fcc3..00000000
--- a/integration_tests/recipes/scipy/patches/0006-Link-openblas-with-modules-that-require-f2c.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From ccbb0fa0884d567c6139eeed7dc2dc9f8db4db3a Mon Sep 17 00:00:00 2001
-From: ryanking13 
-Date: Sun, 28 Jul 2024 18:15:17 +0900
-Subject: [PATCH 06/11] Link openblas with modules that require f2c
-
-Some fortran modules require symbols from f2c, which is provided by
-openblas.
-This patch adds openblas as a dependency to the modules that require f2c
-symbols.
-
-Co-Developed-by: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
----
- scipy/interpolate/meson.build | 2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/scipy/interpolate/meson.build b/scipy/interpolate/meson.build
-index 33783fc034..877a77539c 100644
---- a/scipy/interpolate/meson.build
-+++ b/scipy/interpolate/meson.build
-@@ -172,7 +172,7 @@ py3.extension_module('_dfitpack',
-   f2py_gen.process('src/dfitpack.pyf', extra_args: extra_f2py_arg),
-   c_args: [Wno_unused_variable] +  c_flags_ilp64,
-   link_args: version_link_args,
--  dependencies: [fortranobject_dep],
-+  dependencies: [lapack, fortranobject_dep],
-   link_with: [fitpack_lib],
-   override_options: ['b_lto=false'],
-   install: true,
--- 
-2.39.3 (Apple Git-146)
diff --git a/integration_tests/recipes/scipy/patches/0007-Remove-chla_transtype.patch b/integration_tests/recipes/scipy/patches/0007-Remove-chla_transtype.patch
deleted file mode 100644
index 7e6af9d8..00000000
--- a/integration_tests/recipes/scipy/patches/0007-Remove-chla_transtype.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From 848c94e218e89d866978fbc883cbb2d919f56ce9 Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Wed, 31 Jul 2024 10:29:47 +0200
-Subject: [PATCH 07/11] Remove chla_transtype
-
-The signature should probably be `int chla_transtype(char* res, int *trans)`.
-This just deletes it entirely due to laziness.
-
----
- scipy/linalg/cython_lapack_signatures.txt | 1 -
- 1 file changed, 1 deletion(-)
-
-diff --git a/scipy/linalg/cython_lapack_signatures.txt b/scipy/linalg/cython_lapack_signatures.txt
-index 5aa59d96ea..afdc9480f1 100644
---- a/scipy/linalg/cython_lapack_signatures.txt
-+++ b/scipy/linalg/cython_lapack_signatures.txt
-@@ -111,7 +111,6 @@ void chetrs(char *uplo, int *n, int *nrhs, c *a, int *lda, int *ipiv, c *b, int
- void chetrs2(char *uplo, int *n, int *nrhs, c *a, int *lda, int *ipiv, c *b, int *ldb, c *work, int *info)
- void chfrk(char *transr, char *uplo, char *trans, int *n, int *k, s *alpha, c *a, int *lda, s *beta, c *c)
- void chgeqz(char *job, char *compq, char *compz, int *n, int *ilo, int *ihi, c *h, int *ldh, c *t, int *ldt, c *alpha, c *beta, c *q, int *ldq, c *z, int *ldz, c *work, int *lwork, s *rwork, int *info)
--char chla_transtype(int *trans)
- void chpcon(char *uplo, int *n, c *ap, int *ipiv, s *anorm, s *rcond, c *work, int *info)
- void chpev(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, s *rwork, int *info)
- void chpevd(char *jobz, char *uplo, int *n, c *ap, s *w, c *z, int *ldz, c *work, int *lwork, s *rwork, int *lrwork, int *iwork, int *liwork, int *info)
--- 
-2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0008-Set-wrapper-return-type-to-int.patch b/integration_tests/recipes/scipy/patches/0008-Set-wrapper-return-type-to-int.patch
deleted file mode 100644
index 70cd53dd..00000000
--- a/integration_tests/recipes/scipy/patches/0008-Set-wrapper-return-type-to-int.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From b5d05197de084ab3cab52241f163bae7519b6027 Mon Sep 17 00:00:00 2001
-From: Hood Chatham 
-Date: Wed, 31 Jul 2024 11:48:12 +0200
-Subject: [PATCH 08/11] Set wrapper return type to int
-
----
- scipy/linalg/_generate_pyx.py | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/scipy/linalg/_generate_pyx.py b/scipy/linalg/_generate_pyx.py
-index 8a00f5d279..aeb86e8926 100644
---- a/scipy/linalg/_generate_pyx.py
-+++ b/scipy/linalg/_generate_pyx.py
-@@ -520,7 +520,7 @@ def generate_decl_c(name, return_type, argnames, argtypes, accelerate):
-     if name in WRAPPED_FUNCS:
-         argnames = ['out'] + argnames
-         c_argtypes = [c_return_type] + c_argtypes
--        c_return_type = 'void'
-+        c_return_type = 'int'
-     blas_macro, blas_name = get_blas_macro_and_name(name, accelerate)
-     c_args = ', '.join(f'{t} *{n}' for t, n in zip(c_argtypes, argnames))
-     return f"{c_return_type} {blas_macro}({blas_name})({c_args});\n"
--- 
-2.39.3 (Apple Git-146)
-
diff --git a/integration_tests/recipes/scipy/patches/0010-Explicitly-convert-return-value-of-SUPERLU_MALLOC.patch b/integration_tests/recipes/scipy/patches/0010-Explicitly-convert-return-value-of-SUPERLU_MALLOC.patch
deleted file mode 100644
index 246ac536..00000000
--- a/integration_tests/recipes/scipy/patches/0010-Explicitly-convert-return-value-of-SUPERLU_MALLOC.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From 6a800412b14b5ab905721abe9a509a5e4f44ecef Mon Sep 17 00:00:00 2001
-From: ryanking13 
-Date: Tue, 20 Jan 2026 15:22:19 +0900
-Subject: [PATCH 10/11] Explicitly convert return value of SUPERLU_MALLOC
-
-Fixes incompatible pointer type errors like:
-
-```
-error: incompatible pointer types assigning to 'float *' from 'int *' [-Wincompatible-pointer-types]
-```
-
-Upstream PR:
-https://github.com/scipy/scipy/pull/24408
-
----
- scipy/sparse/linalg/_dsolve/SuperLU/SRC/cgsitrf.c | 2 +-
- scipy/sparse/linalg/_dsolve/SuperLU/SRC/dgsitrf.c | 2 +-
- scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgsitrf.c | 2 +-
- scipy/sparse/linalg/_dsolve/SuperLU/SRC/zgsitrf.c | 2 +-
- 4 files changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/cgsitrf.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/cgsitrf.c
-index 21fb2497b..ae2a3fd2e 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/cgsitrf.c
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/cgsitrf.c
-@@ -299,7 +299,7 @@ cgsitrf(superlu_options_t *options, SuperMatrix *A, int relax, int panel_size,
-     for (k = 0; k < n; k++) iswap[k] = perm_c[k];
-     amax = (float *) SUPERLU_MALLOC(panel_size * sizeof(float));
-     if (drop_rule & DROP_SECONDARY)
--	swork2 = SUPERLU_MALLOC(n * sizeof(float));
-+	swork2 = (float *) SUPERLU_MALLOC(n * sizeof(float));
-     else
- 	swork2 = NULL;
- 
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/dgsitrf.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/dgsitrf.c
-index b3c1ffc15..57f242361 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/dgsitrf.c
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/dgsitrf.c
-@@ -298,7 +298,7 @@ dgsitrf(superlu_options_t *options, SuperMatrix *A, int relax, int panel_size,
-     for (k = 0; k < n; k++) iswap[k] = perm_c[k];
-     amax = (double *) SUPERLU_MALLOC(panel_size * sizeof(double));
-     if (drop_rule & DROP_SECONDARY)
--	dwork2 = SUPERLU_MALLOC(n * sizeof(double));
-+	dwork2 = (double *) SUPERLU_MALLOC(n * sizeof(double));
-     else
- 	dwork2 = NULL;
- 
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgsitrf.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgsitrf.c
-index cc143726f..5c9722c45 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgsitrf.c
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/sgsitrf.c
-@@ -298,7 +298,7 @@ sgsitrf(superlu_options_t *options, SuperMatrix *A, int relax, int panel_size,
-     for (k = 0; k < n; k++) iswap[k] = perm_c[k];
-     amax = (float *) SUPERLU_MALLOC(panel_size * sizeof(float));
-     if (drop_rule & DROP_SECONDARY)
--	swork2 = SUPERLU_MALLOC(n * sizeof(float));
-+	swork2 = (float *) SUPERLU_MALLOC(n * sizeof(float));
-     else
- 	swork2 = NULL;
- 
-diff --git a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/zgsitrf.c b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/zgsitrf.c
-index 4658eaf4c..a60c8119b 100644
---- a/scipy/sparse/linalg/_dsolve/SuperLU/SRC/zgsitrf.c
-+++ b/scipy/sparse/linalg/_dsolve/SuperLU/SRC/zgsitrf.c
-@@ -299,7 +299,7 @@ zgsitrf(superlu_options_t *options, SuperMatrix *A, int relax, int panel_size,
-     for (k = 0; k < n; k++) iswap[k] = perm_c[k];
-     amax = (double *) SUPERLU_MALLOC(panel_size * sizeof(double));
-     if (drop_rule & DROP_SECONDARY)
--	dwork2 = SUPERLU_MALLOC(n * sizeof(double));
-+	dwork2 = (double *) SUPERLU_MALLOC(n * sizeof(double));
-     else
- 	dwork2 = NULL;
- 
--- 
-2.29.2.windows.2
-
diff --git a/integration_tests/recipes/scipy/patches/0011-MAINT-linalg-Remove-dummy-argument-from-larf-wrapper.patch b/integration_tests/recipes/scipy/patches/0011-MAINT-linalg-Remove-dummy-argument-from-larf-wrapper.patch
deleted file mode 100644
index 6762423f..00000000
--- a/integration_tests/recipes/scipy/patches/0011-MAINT-linalg-Remove-dummy-argument-from-larf-wrapper.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 5a684821668bcbbd3a4976c91b4967bfdaee2a59 Mon Sep 17 00:00:00 2001
-From: Ilhan Polat 
-Date: Mon, 5 Jan 2026 01:15:17 +0100
-Subject: [PATCH 11/11] MAINT:linalg: Remove dummy larfg parameter
-
----
-diff --git a/scipy/linalg/flapack_other.pyf.src b/scipy/linalg/flapack_other.pyf.src
-index 1db51bbd83..049344ae5e 100644
---- a/scipy/linalg/flapack_other.pyf.src
-+++ b/scipy/linalg/flapack_other.pyf.src
-@@ -2214,16 +2214,21 @@ function lantr(norm, uplo, diag, m, n, a, lda, work) result(n2)
- 
- end function lantr
- 
--subroutine larfg(n, alpha, x, incx, tau, lx)
-+subroutine larfg(n, alpha, x, incx, tau)
-+    callstatement (*f2py_func)(&n,&alpha,x,&incx,&tau)
-+    callprotoargument F_INT*, *, *, F_INT*, *
-+
-     integer intent(in), check(n>=1) :: n
-      intent(in,out) :: alpha
--     intent(in,copy,out), dimension(lx) :: x
-+     intent(in,copy,out), dimension(1+(n-2)*abs(incx)), depend(n,incx) :: x
-     integer intent(in), check(incx>0||incx<0) :: incx = 1
-      intent(out) :: tau
--    integer intent(hide),depend(x,n,incx),check(lx > (n-2)*incx) :: lx = len(x)
- end subroutine larfg
- 
--subroutine larf(side,m,n,v,incv,tau,c,ldc,work,lwork)
-+subroutine larf(side,m,n,v,incv,tau,c,ldc,work)
-+    callstatement (*f2py_func)(&side,&m,&n,v,&incv,&tau,c,&ldc,work)
-+    callprotoargument char*, F_INT*, F_INT*, *, F_INT*, *, *, F_INT*, *
-+
-     character intent(in), check(side[0]=='L'||side[0]=='R') :: side = 'L'
-     integer intent(in,hide), depend(c) :: m = shape(c,0)
-     integer intent(in,hide), depend(c) :: n = shape(c,1)
-@@ -2233,8 +2238,7 @@ subroutine larf(side,m,n,v,incv,tau,c,ldc,work,lwork)
-      dimension(m,n), intent(in,copy,out) :: c
-     integer intent(in,hide) :: ldc = max(1,shape(c,0))
-     ! FIXME: work should not have been an input argument but kept here for backwards compatibility!
--     intent(in),dimension(lwork),depend(side,m,n) :: work
--    integer intent(hide),depend(work),check(lwork >= (side[0]=='L'?n:m)) :: lwork = len(work)
-+     intent(in), dimension((side[0]=='L'?n:m)), depend(side,m,n) :: work
- end subroutine larf
- 
- subroutine lartg(f,g,cs,sn,r)
diff --git a/integration_tests/recipes/scipy/scipy-conftest.py b/integration_tests/recipes/scipy/scipy-conftest.py
deleted file mode 100644
index 093340b6..00000000
--- a/integration_tests/recipes/scipy/scipy-conftest.py
+++ /dev/null
@@ -1,376 +0,0 @@
-import random
-import re
-import threading
-
-import pytest
-
-xfail = pytest.mark.xfail
-skip = pytest.mark.skip
-
-fp_exception_msg = (
-    "no floating point exceptions, "
-    "see https://github.com/numpy/numpy/pull/21895#issuecomment-1311525881"
-)
-process_msg = "no process support"
-thread_msg = "no thread support"
-todo_signature_mismatch_msg = "TODO signature mismatch"
-todo_memory_corruption_msgt = "TODO memory corruption"
-todo_genuine_difference_msg = "TODO genuine difference to be investigated"
-todo_fp_exception_msg = "TODO did not raise maybe no floating point exception support?"
-todo_overflow_msg = "TODO overflow not raised"
-todo_runtime_warning = "TODO runtime warning not shown"
-
-
-tests_to_mark = [
-    ("test_odeint_jac\\.py", skip, "test module removed: uses Fortran extension not built for WASM"),
-    ("io/tests/test_fortran\\.py", skip, "test module removed: uses Fortran extension not built for WASM"),
-    # scipy/_lib/tests
-    (
-        "test__threadsafety.py::test_parallel_threads",
-        xfail,
-        thread_msg,
-    ),
-    ("test__threadsafety.py::test_parallel_threads", xfail, thread_msg),
-    ("test__util.py::test_pool", xfail, process_msg),
-    ("test__util.py::test_mapwrapper_parallel", xfail, process_msg),
-    ("test__util.py::test__workers_wrapper", xfail, process_msg),
-    ("test_ccallback.py::test_threadsafety", xfail, thread_msg),
-    ("test_import_cycles.py::test_modules_importable", xfail, process_msg),
-    ("test_import_cycles.py::test_public_modules_importable", xfail, process_msg),
-    # scipy/datasets/tests
-    ("test_data.py::TestDatasets", xfail, "TODO datasets not working right now"),
-    # scipy/fft/tests
-    (
-        r"test_basic.py::TestFFT1D.test_dtypes\[float32-numpy\]",
-        xfail,
-        "TODO small floating point difference on the CI but not locally",
-    ),
-    ("test_basic.py::TestFFTThreadSafe", xfail, thread_msg),
-    ("test_basic.py::test_multiprocess", xfail, process_msg),
-    ("test_fft_function.py::test_fft_function", xfail, process_msg),
-    ("test_multithreading.py::test_threaded_same", xfail, thread_msg),
-    (
-        "test_multithreading.py::test_mixed_threads_processes",
-        xfail,
-        thread_msg,
-    ),
-    # scipy/integrate tests
-    ("test__quad_vec.py::TestQuadVec.test_quad_vec_pool.*", xfail, process_msg),
-    (
-        "test_quadpack.py.+TestCtypesQuad.test_ctypes.*",
-        xfail,
-        "Test relying on finding libm.so shared library",
-    ),
-    (
-        "test_quadrature.py.+TestQMCQuad.test_basic",
-        xfail,
-        todo_genuine_difference_msg,
-    ),
-    (
-        "test_quadrature.py.+TestQMCQuad.test_sign",
-        xfail,
-        todo_genuine_difference_msg,
-    ),
-    # scipy/interpolate
-    (
-        "test_fitpack.+test_kink",
-        xfail,
-        "TODO error not raised, maybe due to no floating point exception?",
-    ),
-    (
-        "test_rbf.py::test_rbf_concurrency",
-        xfail,
-        thread_msg,
-    ),
-    # scipy/io
-    (
-        "test_mmio.py::.+fast_matrix_market",
-        xfail,
-        thread_msg,
-    ),
-    (
-        "test_mmio.py::TestMMIOCoordinate.test_precision",
-        xfail,
-        thread_msg,
-    ),
-    (
-        "test_paths.py::TestPaths.test_mmio_(read|write)",
-        xfail,
-        thread_msg,
-    ),
-    # scipy/linalg tests
-    ("test_blas.+test_complex_dotu", skip, todo_signature_mismatch_msg),
-    ("test_cython_blas.+complex", skip, todo_signature_mismatch_msg),
-    ("test_lapack.py.+larfg_larf", skip, todo_signature_mismatch_msg),
-    # scipy/ndimage/tests
-    ("test_filters.py::TestThreading", xfail, thread_msg),
-    # scipy/optimize/tests
-    (
-        "test__differential_evolution.py::"
-        "TestDifferentialEvolutionSolver.test_immediate_updating",
-        xfail,
-        process_msg,
-    ),
-    (
-        "test__differential_evolution.py::TestDifferentialEvolutionSolver.test_parallel",
-        xfail,
-        process_msg,
-    ),
-    (
-        "test__shgo.py.+test_19_parallelization",
-        xfail,
-        process_msg,
-    ),
-    (
-        "test__shgo.py.+",
-        xfail,
-        "Test failing on 32bit (skipped on win32)",
-    ),
-    (
-        "test_linprog.py::TestLinprogSimplexNoPresolve.test_bounds_infeasible_2",
-        xfail,
-        "TODO no warnings emitted maybe due to no floating point exception?",
-    ),
-    ("test_minpack.py::TestFSolve.test_concurrent.+", xfail, process_msg),
-    ("test_minpack.py::TestLeastSq.test_concurrent.+", xfail, process_msg),
-    ("test_optimize.py::test_cobyla_threadsafe", xfail, thread_msg),
-    ("test_optimize.py::TestBrute.test_workers", xfail, process_msg),
-    (
-        "test__numdiff.py::TestApproxDerivativesDense.test_scalar_vector",
-        xfail,
-        process_msg,
-    ),
-    (
-        "test__numdiff.py::TestApproxDerivativesDense.test_workers_evaluations_and_nfev",
-        xfail,
-        process_msg,
-    ),
-    (
-        "test__numdiff.py::TestApproxDerivativesDense.test_vector_vector",
-        xfail,
-        process_msg,
-    ),
-    (
-        "test__numdiff.py::TestApproxDerivativeSparse.test_all",
-        xfail,
-        process_msg,
-    ),
-    (
-        ".*test_workers.*",
-        xfail,
-        process_msg,
-    ),
-    (
-        "test_optimize.py::TestWorkers.*",
-        xfail,
-        process_msg,
-    ),
-    (
-        "test_optimize.py::test_multiprocessing_too_many_open_files_23080",
-        xfail,
-        process_msg,
-    ),
-    # scipy/signal/tests
-    (
-        "test_signaltools.py::TestMedFilt.test_medfilt2d_parallel",
-        xfail,
-        thread_msg,
-    ),
-    # scipy/sparse/tests
-    ("test_arpack.py::test_parallel_threads", xfail, thread_msg),
-    ("test_array_api.py::test_sparse_dense_divide", xfail, fp_exception_msg),
-    ("test_linsolve.py::TestSplu.test_threads_parallel", xfail, thread_msg),
-    ("test_propack", skip, todo_signature_mismatch_msg),
-    ("test_sparsetools.py::test_threads", xfail, thread_msg),
-    # scipy/sparse/csgraph/tests
-    ("test_shortest_path.py::test_gh_17782_segfault", xfail, thread_msg),
-    # scipy/sparse/linalg/tests
-    ("test_svds.py::Test_SVDS_PROPACK", skip, todo_signature_mismatch_msg),
-    # scipy/spatial/tests
-    (
-        "test_kdtree.py::test_query_ball_point_multithreading",
-        xfail,
-        thread_msg,
-    ),
-    ("test_kdtree.py::test_ckdtree_parallel", xfail, thread_msg),
-    # scipy/special/tests
-    (
-        "test_exponential_integrals.py::TestExp1.test_branch_cut",
-        xfail,
-        "TODO maybe float support since +0 and -0 difference",
-    ),
-    (
-        "test_round.py::test_add_round_(up|down)",
-        xfail,
-        "TODO small floating point difference, maybe due to lack of floating point "
-        "support for controlling rounding, see "
-        "https://github.com/WebAssembly/design/issues/1384",
-    ),
-    (
-        # This test is skipped for PyPy as well, maybe for a related reason?,
-        # see
-        # https://github.com/conda-forge/scipy-feedstock/pull/196#issuecomment-979317832
-        "test_distributions.py::TestBeta.test_boost_eval_issue_14606",
-        skip,
-        "TODO C++ exception that causes a Pyodide fatal error",
-    ),
-    # The following four tests do not raise the required
-    # 
-    (
-        "test_basic.py::test_error_raising",
-        xfail,
-        todo_fp_exception_msg,
-    ),
-    (
-        "test_sf_error.py::test_errstate_pyx_basic",
-        xfail,
-        todo_fp_exception_msg,
-    ),
-    (
-        "test_sf_error.py::test_errstate_cpp_scipy_special",
-        xfail,
-        todo_fp_exception_msg,
-    ),
-    (
-        "test_sf_error.py::test_errstate_cpp_alt_ufunc_machinery",
-        xfail,
-        todo_fp_exception_msg,
-    ),
-    (
-        "test_sf_error.py::test_check_overflow_message",
-        xfail,
-        todo_overflow_msg,
-    ),
-    (
-        "test_kdeoth.py::test_kde_[12]d",
-        xfail,
-        todo_genuine_difference_msg,
-    ),
-    (
-        "test_multivariate.py::TestMultivariateT.test_cdf_against_generic_integrators",
-        skip,
-        "TODO tplquad integration does not seem to converge",
-    ),
-    (
-        "test_multivariate.py::TestCovariance.test_mvn_with_covariance_cdf.+Precision-size1",
-        xfail,
-        "TODO small floating point difference 6e-7 relative diff instead of 1e-7",
-    ),
-    (
-        "test_multivariate.py::TestMultivariateNormal.test_logcdf_default_values",
-        xfail,
-        todo_genuine_difference_msg,
-    ),
-    (
-        "test_multivariate.py::TestMultivariateNormal.test_broadcasting",
-        xfail,
-        todo_genuine_difference_msg,
-    ),
-    (
-        "test_multivariate.py::TestMultivariateNormal.test_normal_1D",
-        xfail,
-        todo_genuine_difference_msg,
-    ),
-    (
-        "test_multivariate.py::TestMultivariateNormal.test_R_values",
-        xfail,
-        todo_genuine_difference_msg,
-    ),
-    (
-        "test_multivariate.py::TestMultivariateNormal.test_cdf_with_lower_limit",
-        xfail,
-        todo_genuine_difference_msg,
-    ),
-    (
-        "test_multivariate.py::TestMultivariateT.test_cdf_against_multivariate_normal",
-        xfail,
-        todo_genuine_difference_msg,
-    ),
-    ("test_qmc.py::TestVDC.test_van_der_corput", xfail, thread_msg),
-    ("test_qmc.py::TestHalton.test_workers", xfail, thread_msg),
-    ("test_qmc.py::TestUtils.test_discrepancy_parallel", skip, "thread constructor fails and leaves C destructor with WASM function-pointer mismatch, causing a fatal error during pytest GC cleanup"),
-    (
-        "test_qmc.py::TestMultivariateNormalQMC.test_validations",
-        xfail,
-        todo_fp_exception_msg,
-    ),
-    (
-        "test_qmc.py::TestMultivariateNormalQMC.test_MultivariateNormalQMCDegenerate",
-        xfail,
-        todo_genuine_difference_msg,
-    ),
-    ("test_sampling.py::test_threading_behaviour", xfail, thread_msg),
-    ("test_stats.py::TestMGCStat.test_workers", xfail, process_msg),
-    (
-        "test_stats.py::TestKSTwoSamples.testLargeBoth",
-        skip,
-        "TODO test taking > 5 minutes after scipy 1.10.1 update",
-    ),
-    (
-        "test_stats.py::TestKSTwoSamples.test_some_code_paths",
-        xfail,
-        todo_fp_exception_msg,
-    ),
-    (
-        "test_stats.py::TestGeometricStandardDeviation.test_raises_value_error",
-        xfail,
-        todo_fp_exception_msg,
-    ),
-    (
-        "test_stats.py::TestBrunnerMunzel.test_brunnermunzel_normal_dist",
-        xfail,
-        fp_exception_msg,
-    ),
-    (
-        "test_fit.py::test_fit_error",
-        xfail,
-        todo_runtime_warning,
-    ),
-    (
-        "test_stats.py::TestWassersteinDistance.test_inf_values",
-        xfail,
-        todo_runtime_warning,
-    ),
-    (
-        "test_stats.py::TestEnergyDistance.test_inf_values",
-        xfail,
-        todo_runtime_warning,
-    ),
-    # many
-    (".*test_concurrency.*", xfail, thread_msg),
-]
-
-
-def pytest_configure(config):
-    # threading.get_native_id is not available in Pyodide's WASM environment
-    if not hasattr(threading, "get_native_id"):
-        threading.get_native_id = lambda: random.randint(0, 10000)
-
-
-@pytest.hookimpl(trylast=True)
-def pytest_sessionfinish(session, exitstatus):  # noqa: ARG001
-    # C-extension destructors in SciPy call Fortran functions with void/int
-    # signature mismatches. These run both
-    # during the gc cleanup (gc_collect_harder in _pytest/unraisableexception)
-    # and during Python's own finalization sequence, causing fatal errors that
-    # cannot be caught in Python as they crash the interpreter. os._exit can
-    # at least bypass both of these.
-    import os
-    import sys
-
-    # For outputs (can't get this to work)
-    # sys.stdout.flush()
-    # sys.stderr.flush()
-    # test summary line doesn't work so we can't see how many passed/skipped/etc...
-    os._exit(int(exitstatus))
-
-
-def pytest_collection_modifyitems(config, items):
-    for item in items:
-        path, line, name = item.reportinfo()
-        path = str(path)
-        full_name = f"{path}::{name}"
-        for pattern, mark, reason in tests_to_mark:
-            if re.search(pattern, full_name):
-                # print(full_name)
-                item.add_marker(mark(reason=reason))
diff --git a/integration_tests/recipes/scipy/test_scipy.py b/integration_tests/recipes/scipy/test_scipy.py
deleted file mode 100644
index fc018ab5..00000000
--- a/integration_tests/recipes/scipy/test_scipy.py
+++ /dev/null
@@ -1,214 +0,0 @@
-import pytest
-from pytest_pyodide import run_in_pyodide
-
-from conftest import package_is_built
-
-
-@pytest.mark.driver_timeout(40)
-@run_in_pyodide(packages=["scipy"])
-def test_scipy_linalg(selenium):
-    import numpy as np
-    import scipy.linalg
-    from numpy.testing import assert_allclose
-
-    N = 10
-    X = np.random.RandomState(42).rand(N, N)
-
-    X_inv = scipy.linalg.inv(X)
-
-    res = X.dot(X_inv)
-
-    assert_allclose(res, np.identity(N), rtol=1e-07, atol=1e-9)
-
-
-@pytest.mark.driver_timeout(40)
-@run_in_pyodide(packages=["scipy"])
-def test_brentq(selenium):
-    from scipy.optimize import brentq
-
-    brentq(lambda x: x, -1, 1)
-
-
-@pytest.mark.driver_timeout(40)
-@run_in_pyodide(packages=["scipy"])
-def test_dlamch(selenium):
-    from scipy.linalg import lapack
-
-    lapack.dlamch("Epsilon-Machine")
-
-
-@pytest.mark.driver_timeout(40)
-@run_in_pyodide(packages=["scipy"])
-def test_binom_ppf(selenium):
-    from scipy.stats import binom
-
-    assert binom.ppf(0.9, 1000, 0.1) == 112
-
-
-_scipy_test_packages = ["pytest", "scipy", "micropip"] + (
-    ["scipy-tests"] if package_is_built("scipy-tests") else []
-)
-
-
-@pytest.mark.xfail_browsers(node="Can't fetch metadata for 'hypothesis'")
-@pytest.mark.skip_pyproxy_check
-@pytest.mark.driver_timeout(40)
-@run_in_pyodide(packages=_scipy_test_packages)
-async def test_scipy_pytest(selenium):
-    import pytest
-
-    import micropip
-
-    await micropip.install("hypothesis")
-
-    def runtest(module, filter):
-        result = pytest.main(
-            [
-                "--pyargs",
-                f"scipy.{module}",
-                "--continue-on-collection-errors",
-                "-vv",
-                "-k",
-                filter,
-            ]
-        )
-        assert result == 0
-
-    runtest("odr", "explicit")
-    runtest("stats.tests.test_multivariate", "haar")
-
-    # function signature mismatch with PROPACK, works with LOBPCG and ARPACK.
-    # Restore this when updating scipy
-    # runtest("sparse.linalg._eigen", "test_svds_parameter_k_which")
-    runtest(
-        "sparse.linalg._eigen.tests.test_svds",
-        "(not Test_SVDS_PROPACK) and test_svds_parameter_k_which",
-    )
-
-
-@pytest.mark.driver_timeout(40)
-@run_in_pyodide(packages=["scipy"])
-def test_cpp_exceptions(selenium):
-    import numpy as np
-    import pytest
-    from scipy.spatial.distance import cdist
-
-    out = np.ones((2, 2))
-    arr = np.array([[1, 2]])
-
-    with pytest.raises(ValueError, match="Output array has incorrect shape"):
-        cdist(arr, arr, out=out)
-    from scipy.sparse._sparsetools import test_throw_error
-
-    with pytest.raises(MemoryError):
-        test_throw_error()
-    from scipy.signal import lombscargle
-
-    with pytest.raises(ValueError):
-        lombscargle(x=[1], y=[1, 2], freqs=[1, 2, 3])
-
-
-# Regression test for LAPACK larfg signature mismatch
-# https://github.com/pyodide/pyodide/issues/3379
-@pytest.mark.driver_timeout(40)
-@run_in_pyodide(packages=["scipy", "numpy"])
-def test_lapack_larfg(selenium):
-    import numpy as np
-    from scipy.linalg.lapack import get_lapack_funcs
-
-    a = np.arange(16).reshape(4, 4)
-    a = a.T.dot(a)
-
-    (larfg,) = get_lapack_funcs(["larfg"], dtype="float64")
-    alpha, x, tau = larfg(a.shape[0] - 1, a[1, 0], a[2:, 0])
-    return (alpha, x, tau) is not None
-
-
-@pytest.mark.driver_timeout(40)
-@run_in_pyodide(packages=["scipy"])
-def test_logm(selenium_standalone):
-    import numpy as np
-    from numpy import eye, random
-    from scipy.linalg import logm
-
-    random.seed(1234)
-    dtype = np.float64
-    n = 2
-    scale = 1e-4
-    A = (eye(n) + random.rand(n, n) * scale).astype(dtype)
-    logm(A)
-
-
-@pytest.mark.driver_timeout(40)
-@run_in_pyodide(packages=["scipy"])
-def test_dblquad(selenium):
-    import scipy.integrate
-
-    unit_square_area = scipy.integrate.dblquad(
-        lambda y, x: 1, 0, 1, lambda x: 0, lambda x: 1
-    )
-    assert abs(unit_square_area[0] - 1) < unit_square_area[1], (
-        f"Unit square area calculated using scipy.integrate.dblquad of {unit_square_area[0]} (+- {unit_square_area[0]}) is too far from 1.0"
-    )
-
-
-import shutil
-import subprocess
-from contextlib import contextmanager
-from pathlib import Path
-from typing import TYPE_CHECKING, Any
-
-
-def check_emscripten():
-    if not shutil.which("emcc"):
-        pytest.skip("Needs Emscripten")
-
-
-@contextmanager
-def venv_ctxmgr(path):
-    check_emscripten()
-
-    if TYPE_CHECKING:
-        create_pyodide_venv: Any = None
-    else:
-        from pyodide_build.out_of_tree.venv import create_pyodide_venv
-
-    create_pyodide_venv(path)
-    try:
-        yield path
-    finally:
-        shutil.rmtree(path, ignore_errors=True)
-
-
-@pytest.fixture(scope="module")
-def venv(runtime):
-    if runtime != "node":
-        pytest.xfail("node only")
-    check_emscripten()
-    path = Path(".venv-pyodide-tmp-test")
-    with venv_ctxmgr(path) as venv:
-        yield venv
-
-
-def install_pkg(venv, pkgname):
-    return subprocess.run(
-        [
-            venv / "bin/pip",
-            "install",
-            pkgname,
-            "--disable-pip-version-check",
-        ],
-        capture_output=True,
-        encoding="utf8",
-    )
-
-
-def test_cmdline_runner(selenium, venv):
-    result = install_pkg(venv, "scipy")
-    assert result.returncode == 0
-    result = subprocess.run(
-        [venv / "bin/python", Path(__file__).parent / "cmdline_test_file.py"]
-    )
-    print(result.stdout)
-    print(result.stderr)
-    assert result.returncode == 0

From 9715cf427ec2fe0144c924161e2da3711996bdf9 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 6 Jun 2026 19:02:23 +0530
Subject: [PATCH 33/71] Add f2py example for testing

---
 .../recipes/f2py-example/meta.yaml            | 34 +++++++++++++
 .../source/f2py_example/__init__.py           |  3 ++
 .../recipes/f2py-example/source/meson.build   | 48 +++++++++++++++++++
 .../f2py-example/source/pyproject.toml        |  9 ++++
 .../f2py-example/source/src/fibonacci.f       | 18 +++++++
 5 files changed, 112 insertions(+)
 create mode 100644 integration_tests/recipes/f2py-example/meta.yaml
 create mode 100644 integration_tests/recipes/f2py-example/source/f2py_example/__init__.py
 create mode 100644 integration_tests/recipes/f2py-example/source/meson.build
 create mode 100644 integration_tests/recipes/f2py-example/source/pyproject.toml
 create mode 100644 integration_tests/recipes/f2py-example/source/src/fibonacci.f

diff --git a/integration_tests/recipes/f2py-example/meta.yaml b/integration_tests/recipes/f2py-example/meta.yaml
new file mode 100644
index 00000000..19900e14
--- /dev/null
+++ b/integration_tests/recipes/f2py-example/meta.yaml
@@ -0,0 +1,34 @@
+package:
+  name: f2py-example
+  version: 0.1.0
+  top-level:
+    - f2py_example
+
+source:
+  path: source
+
+build:
+  cflags: |
+    -I$(WASM_LIBRARY_DIR)/include
+  script: |
+    git clone https://github.com/hoodmane/f2c.git --depth 1
+    (cd f2c/src && cp makefile.u makefile && sed -i "s/gram.c:/gram.c1:/" makefile && make)
+    export F2C_PATH=$(pwd)/f2c/src/f2c
+    cp f2c/f2c.h ${WASM_LIBRARY_DIR}/include/f2c.h
+
+requirements:
+  host:
+    - numpy
+  run:
+    - numpy
+  executable:
+    - gfortran
+
+about:
+  home: https://github.com/pyodide/pyodide-build
+  summary: Minimal Fortran/f2py integration test (Fibonacci, loosely based on github.com/larsbuntemeyer/pyfort)
+  license: MIT
+
+extra:
+  recipe-maintainers:
+    - agriyakhetarpal
diff --git a/integration_tests/recipes/f2py-example/source/f2py_example/__init__.py b/integration_tests/recipes/f2py-example/source/f2py_example/__init__.py
new file mode 100644
index 00000000..b454c205
--- /dev/null
+++ b/integration_tests/recipes/f2py-example/source/f2py_example/__init__.py
@@ -0,0 +1,3 @@
+from .fib import fib
+
+__all__ = ["fib"]
diff --git a/integration_tests/recipes/f2py-example/source/meson.build b/integration_tests/recipes/f2py-example/source/meson.build
new file mode 100644
index 00000000..b03ef4f1
--- /dev/null
+++ b/integration_tests/recipes/f2py-example/source/meson.build
@@ -0,0 +1,48 @@
+project('f2py-example', 'c',
+  version: '0.1.0',
+  license: 'MIT',
+  meson_version: '>= 1.3.0',
+  default_options: [
+    'buildtype=debugoptimized',
+    'c_args=-Wno-unused-function -Wno-conversion -Wno-misleading-indentation -Wno-incompatible-pointer-types',
+    'fortran_args=-Wno-conversion',
+    'fortran_std=legacy',
+  ],
+)
+
+add_languages('fortran', native: false)
+
+py_mod = import('python')
+py3 = py_mod.find_installation()
+py3_dep = py3.dependency()
+
+numpy_cflags = run_command('numpy-config', '--cflags', check: true).stdout().strip().split()
+
+f2py = find_program('f2py')
+
+incdir_f2py = run_command(py3,
+  ['-c', 'from numpy import f2py; print(f2py.get_include())'],
+  check: true
+).stdout().strip()
+
+fib_source = custom_target('fibmodule.c',
+  input: ['src/fibonacci.f'],
+  output: ['fibmodule.c', 'fib-f2pywrappers.f'],
+  command: [f2py, '@INPUT@', '-m', 'fib', '--lower']
+)
+
+inc_dirs = include_directories(incdir_f2py)
+
+py3.install_sources(['f2py_example/__init__.py'],
+  pure: false,
+  subdir: 'f2py_example')
+
+py3.extension_module('fib',
+  ['src/fibonacci.f', fib_source],
+  incdir_f2py / 'fortranobject.c',
+  include_directories: inc_dirs,
+  c_args: numpy_cflags,
+  dependencies: py3_dep,
+  install: true,
+  subdir: 'f2py_example',
+)
diff --git a/integration_tests/recipes/f2py-example/source/pyproject.toml b/integration_tests/recipes/f2py-example/source/pyproject.toml
new file mode 100644
index 00000000..04b25664
--- /dev/null
+++ b/integration_tests/recipes/f2py-example/source/pyproject.toml
@@ -0,0 +1,9 @@
+[build-system]
+build-backend = "mesonpy"
+requires = ["meson-python", "numpy"]
+
+[project]
+name = "f2py-example"
+version = "0.1.0"
+requires-python = ">=3.9"
+dependencies = ["numpy"]
diff --git a/integration_tests/recipes/f2py-example/source/src/fibonacci.f b/integration_tests/recipes/f2py-example/source/src/fibonacci.f
new file mode 100644
index 00000000..e2dd9bff
--- /dev/null
+++ b/integration_tests/recipes/f2py-example/source/src/fibonacci.f
@@ -0,0 +1,18 @@
+C FILE: FIBONACCI.F
+C Loosely based on the pyfort example by Lars Buntemeyer (MIT licence)
+C https://github.com/larsbuntemeyer/pyfort
+      SUBROUTINE FIB(A, N)
+C     Calculate first N Fibonacci numbers
+      INTEGER N
+      REAL*8 A(N)
+      DO I = 1, N
+         IF (I .EQ. 1) THEN
+            A(I) = 0.0D0
+         ELSEIF (I .EQ. 2) THEN
+            A(I) = 1.0D0
+         ELSE
+            A(I) = A(I-1) + A(I-2)
+         ENDIF
+      ENDDO
+      END
+C END FILE FIBONACCI.F

From aedf9b83e94d478d44a30779fcb16487468dfefb Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sun, 7 Jun 2026 01:09:05 +0530
Subject: [PATCH 34/71] Fix grammar in `get_unisolated_packages` docstring

---
 pyodide_build/build_env.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py
index cb9aa4c1..b175fba8 100644
--- a/pyodide_build/build_env.py
+++ b/pyodide_build/build_env.py
@@ -228,8 +228,8 @@ def get_unisolated_packages() -> dict[str, str]:
 
     Unisolated packages are packages that are used during the build process
     and have some platform-specific files. When these packages are used
-    during the build process, we switch need to switch platform-specific files,
-    in order to build the package correctly.
+    during the build process, their platform-specific files are replaced with
+    WASM-compatible versions to build the package correctly.
 
     Returns
     -------

From 14749d113cee9b11ee3fc6795b657a27027d06c7 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sun, 7 Jun 2026 01:10:55 +0530
Subject: [PATCH 35/71] Fix docstring for `get_unisolated_files`

---
 pyodide_build/build_env.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py
index b175fba8..344b1512 100644
--- a/pyodide_build/build_env.py
+++ b/pyodide_build/build_env.py
@@ -267,7 +267,9 @@ def get_unisolated_files(package_name: str) -> tuple[Path, list[str]]:
 
     Returns
     -------
-    A tuple of the package directory and a list of file paths relative to the package directory.
+    A tuple of (base_dir, relative_paths) where base_dir is the root directory
+    containing all unisolated packages (e.g. site-packages-extras) and
+    relative_paths is the list of file paths for this package relative to base_dir.
 
     """
     PYODIDE_ROOT = get_pyodide_root()

From daecc1a0315f27141e025910c45d391232a06ab9 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sun, 7 Jun 2026 01:11:15 +0530
Subject: [PATCH 36/71] Fix param name mismatch (`venv_path`)

---
 pyodide_build/pypabuild.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 5d9548b5..2c1a1d6e 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -149,7 +149,7 @@ def _install_cross_build_files(venv_path: str, unisolated: set[str]) -> None:
 
     Parameters
     ----------
-    path
+    venv_path
         The path to the isolated environment.
 
     unisolated

From 48e674d5f7db2ddce48014d2a014873e9fd04ee7 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sun, 7 Jun 2026 01:12:24 +0530
Subject: [PATCH 37/71] Use warning instead of bare print

---
 pyodide_build/pypabuild.py | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 2c1a1d6e..73ab2922 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -4,6 +4,7 @@
 import subprocess as sp
 import sys
 import traceback
+import warnings
 from collections.abc import Callable, Iterator, Mapping, Sequence
 from contextlib import contextmanager
 from pathlib import Path
@@ -131,10 +132,12 @@ def _replace_unisolated_packages(
             if req.name == name:
                 # TODO: find a better way to handle this case
                 if not req.specifier.contains(version):
-                    print(
-                        f"WARNING: found build dependency {req} but the only supported cross-build version is {name}=={version}"
+                    warnings.warn(
+                        f"Found build dependency {req} but the only supported "
+                        f"cross-build version is {name}=={version}; "
+                        f"using {name}=={version} instead.",
+                        stacklevel=2,
                     )
-                    print(f"WARNING: using {name}=={version} instead")
                 new_reqs.discard(reqstr)
                 new_reqs.add(f"{name}=={version}")
                 unisolated.add(name)

From 1821d6c8970e4c30aed02721a377a150bb30741c Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sun, 7 Jun 2026 01:13:01 +0530
Subject: [PATCH 38/71] Deprecation warning for
 `skip_install_cross_build_packages`

---
 pyodide_build/xbuildenv.py | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/pyodide_build/xbuildenv.py b/pyodide_build/xbuildenv.py
index 6212e4db..eca1d40c 100644
--- a/pyodide_build/xbuildenv.py
+++ b/pyodide_build/xbuildenv.py
@@ -165,6 +165,15 @@ def install(
         Path to the root directory for the cross-build environment.
         """
 
+        if not skip_install_cross_build_packages:
+            import warnings
+
+            warnings.warn(
+                "skip_install_cross_build_packages is deprecated and no longer has any effect.",
+                DeprecationWarning,
+                stacklevel=2,
+            )
+
         if url and version:
             raise ValueError("Cannot specify both version and url")
 

From 5bb795ccb89aade5fb41a4a58941ce9590f2f46c Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sun, 7 Jun 2026 01:15:25 +0530
Subject: [PATCH 39/71] Be a bit more defensive about xbuildenv reqs file

---
 pyodide_build/build_env.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py
index 344b1512..bea2e7dc 100644
--- a/pyodide_build/build_env.py
+++ b/pyodide_build/build_env.py
@@ -242,7 +242,14 @@ def get_unisolated_packages() -> dict[str, str]:
         unisolated_packages_file = PYODIDE_ROOT / ".." / "requirements.txt"
 
         for line in unisolated_packages_file.read_text().splitlines():
-            name, version = line.split("==")
+            line = line.strip()
+            # The xbuildenv requirements.txt is machine-generated and always
+            # uses pinned name==version entries, but we skip blank lines,
+            # comments, and any non-pinned specs just in case. Shouldn't
+            # really happen though.
+            if not line or line.startswith("#") or "==" not in line:
+                continue
+            name, version = line.split("==", 1)
             unisolated_packages[name] = version
     else:
         from pyodide_build.recipe.loader import load_all_recipes

From 25f0ce40ad857395d5c77b9fd94b884500a6912b Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sun, 7 Jun 2026 01:24:46 +0530
Subject: [PATCH 40/71] Add CHANGELOG entries for #21

---
 CHANGELOG.md | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 235dc610..7ed30bce 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,31 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## [0.35.0] - 2026/XX/XX
+
+### Changed
+
+- Unisolated packages are now installed into the isolated build environment via
+  pip, with their cross-build files replaced by WASM-compatible versions from
+  the cross-build environment. This makes build-time scripts exposed by these
+  packages available on `PATH` during the build process.
+  [#21](https://github.com/pyodide/pyodide-build/pull/21)
+
+- `oldest-supported-numpy` is no longer silently ignored when encountered as a
+  build-time dependency. It will now be installed as any other package. Since
+  `oldest-supported-numpy` is deprecated since NumPy 2.0, packages that still
+  list it should migrate to a direct `numpy` dependency. If you need to ignore
+  it (or any other build requirement), set it via
+  `pyodide config set ignored_build_requirements "patchelf oldest-supported-numpy"`
+  [#21](https://github.com/pyodide/pyodide-build/pull/21)
+
+- The `skip_install_cross_build_packages` parameter of
+  `CrossBuildEnvManager.install()` is deprecated and no longer has any effect.
+  Cross-build files are now copied into the isolated build environment's
+  site-packages at package build time, rather than being pre-installed into
+  a shared directory inside the xbuildenv at install time.
+  [#21](https://github.com/pyodide/pyodide-build/pull/21)
+
 ## [0.34.5] - 2026/05/20
 
 ### Added

From 4f88027763610205a6f7945f4b8f9c3950e4f18f Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sun, 7 Jun 2026 01:33:52 +0530
Subject: [PATCH 41/71] Fix license compliance for pypa/build

---
 pyodide_build/vendor/LICENSE       | 20 ++++++++++++++++++++
 pyodide_build/vendor/_pypabuild.py | 25 ++++---------------------
 pyproject.toml                     |  2 +-
 3 files changed, 25 insertions(+), 22 deletions(-)
 create mode 100644 pyodide_build/vendor/LICENSE

diff --git a/pyodide_build/vendor/LICENSE b/pyodide_build/vendor/LICENSE
new file mode 100644
index 00000000..c3713cdc
--- /dev/null
+++ b/pyodide_build/vendor/LICENSE
@@ -0,0 +1,20 @@
+Copyright © 2019 Filipe Laíns 
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/pyodide_build/vendor/_pypabuild.py b/pyodide_build/vendor/_pypabuild.py
index 0788500c..da94c364 100644
--- a/pyodide_build/vendor/_pypabuild.py
+++ b/pyodide_build/vendor/_pypabuild.py
@@ -1,25 +1,8 @@
 # This file contains private functions taken from pypa/build.
-
-# Copyright © 2019 Filipe Laíns 
-
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the "Software"),
-# to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense,
-# and/or sell copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following conditions:
-
-# The above copyright notice and this permission notice (including the next
-# paragraph) shall be included in all copies or substantial portions of the
-# Software.
-
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
-# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-# DEALINGS IN THE SOFTWARE.
+# See license at LICENSE next to this file and as defined in
+# pyproject.toml. For built distributions of pyodide-build,
+# you may obtain a copy of the license in the
+# .dist-info/licenses directory.
 import contextlib
 import contextvars
 import os
diff --git a/pyproject.toml b/pyproject.toml
index add5d6ff..33e8da07 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ classifiers = [
     "Operating System :: OS Independent",
 ]
 license = "MPL-2.0"
-license-files = ["LICENSE"]
+license-files = ["LICENSE", "pyodide_build/vendor/LICENSE"]
 requires-python = ">=3.12"
 dependencies = [
     "build>=1.4,<1.6,!=1.4.4", # keep in sync with uv extra

From 10275a00e2e61b3c016522631ce056ae63b8f1f0 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sun, 7 Jun 2026 19:45:02 +0530
Subject: [PATCH 42/71] Restore logic to install cross-build packages

---
 CHANGELOG.md                          |   7 --
 pyodide_build/pypabuild.py            |   6 ++
 pyodide_build/recipe/builder.py       |  45 ++++++++--
 pyodide_build/tests/test_xbuildenv.py |  60 +++++++++++++
 pyodide_build/xbuildenv.py            | 117 +++++++++++++++++++++++---
 5 files changed, 211 insertions(+), 24 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 99e5cf75..70ce3f7f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -41,13 +41,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   `pyodide config set ignored_build_requirements "patchelf oldest-supported-numpy"`
   [#21](https://github.com/pyodide/pyodide-build/pull/21)
 
-- The `skip_install_cross_build_packages` parameter of
-  `CrossBuildEnvManager.install()` is deprecated and no longer has any effect.
-  Cross-build files are now copied into the isolated build environment's
-  site-packages at package build time, rather than being pre-installed into
-  a shared directory inside the xbuildenv at install time.
-  [#21](https://github.com/pyodide/pyodide-build/pull/21)
-
 ## [0.34.4] - 2026/05/15
 
 ### Added
diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 423d2c4a..085063a0 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -17,10 +17,12 @@
 from pyodide_build import _f2c_fixes, common, pywasmcross, uv_helper
 from pyodide_build.build_env import (
     get_build_flag,
+    get_current_xbuildenv_manager,
     get_host_build_flag,
     get_pyversion,
     get_unisolated_files,
     get_unisolated_packages,
+    in_xbuildenv,
     platform,
 )
 from pyodide_build.spec import _BuildSpecExports
@@ -207,6 +209,10 @@ def install_reqs(
     ]
     reqs, unisolated = _replace_unisolated_packages(reqs, get_unisolated_packages())
     reqs = remove_avoided_requirements(reqs, IGNORED_BUILD_REQUIREMENTS)
+
+    if in_xbuildenv() and unisolated:
+        get_current_xbuildenv_manager().ensure_cross_build_packages_installed()
+
     # propagate PIP config from build_env to current environment
     with common.replace_env(
         os.environ | {k: v for k, v in build_env.items() if k.startswith("PIP")}
diff --git a/pyodide_build/recipe/builder.py b/pyodide_build/recipe/builder.py
index 5eb2d21b..30942427 100755
--- a/pyodide_build/recipe/builder.py
+++ b/pyodide_build/recipe/builder.py
@@ -640,13 +640,46 @@ def _package_wheel(
                 Path(self.build_args.host_install_dir)
                 / f"lib/{python_dir}/site-packages"
             )
-            # Copy cross build files to host site packages
-            for cross_build_file in self.build_metadata.cross_build_files:
-                src_file = wheel_dir / cross_build_file
-                dest_file = host_site_packages / cross_build_file
-                dest_file.parent.mkdir(parents=True, exist_ok=True)
+            if self.build_metadata.cross_build_env:
+                subprocess.run(
+                    [
+                        "pip",
+                        "install",
+                        # Upgrade the package in the host environment if there is a
+                        # older or newer version of the package already installed.
+                        # However, we don't want to replace the dependencies of the package,
+                        # since they may contain cross-build files as well.
+                        # For instance, numpy and scipy are both cross-build packages, but scipy depends on numpy.
+                        # Therefore, if we install numpy first and then scipy, installing scipy
+                        # will overwrite the cross build files in numpy.
+                        "--upgrade",
+                        "--no-deps",
+                        "-t",
+                        str(host_site_packages),
+                        f"{name}=={ver}",
+                    ],
+                    check=True,
+                )
+
+                # Call the same pip command again to install the dependencies
+                # but without the --upgrade flag. This will prevent pip from
+                # overwriting the dependencies in the host environment.
+                subprocess.run(
+                    [
+                        "pip",
+                        "install",
+                        "-t",
+                        str(host_site_packages),
+                        f"{name}=={ver}",
+                    ],
+                    check=True,
+                )
 
-                shutil.copy(src_file, dest_file)
+            for cross_build_file in self.build_metadata.cross_build_files:
+                shutil.copy(
+                    (wheel_dir / cross_build_file),
+                    host_site_packages / cross_build_file,
+                )
 
 
 class RecipeBuilderStaticLibrary(RecipeBuilder):
diff --git a/pyodide_build/tests/test_xbuildenv.py b/pyodide_build/tests/test_xbuildenv.py
index 612511fa..cc536ee3 100644
--- a/pyodide_build/tests/test_xbuildenv.py
+++ b/pyodide_build/tests/test_xbuildenv.py
@@ -277,6 +277,41 @@ def test_install_force(
         assert (tmp_path / version / ".installed").exists()
         assert manager.current_version == version
 
+    def test_install_cross_build_packages(
+        self, tmp_path, dummy_xbuildenv_url, monkeypatch_subprocess_run_pip
+    ):
+        pip_called_with = monkeypatch_subprocess_run_pip
+        manager = CrossBuildEnvManager(tmp_path)
+
+        download_path = tmp_path / "test"
+        download_and_unpack_archive(dummy_xbuildenv_url, download_path, "")
+
+        xbuildenv_root = download_path / "xbuildenv"
+        xbuildenv_pyodide_root = xbuildenv_root / "pyodide-root"
+        manager._install_cross_build_packages(xbuildenv_root, xbuildenv_pyodide_root)
+
+        assert len(pip_called_with) == 9
+        assert pip_called_with[0:8] == [
+            sys.executable,
+            "-m",
+            "pip",
+            "install",
+            "--no-user",
+            "-r",
+            str(xbuildenv_root / "requirements.txt"),
+            "--target",
+        ]
+        assert pip_called_with[8].startswith(
+            str(xbuildenv_pyodide_root)
+        )  # hostsitepackages
+
+        hostsitepackages = manager._host_site_packages_dir(xbuildenv_pyodide_root)
+        assert hostsitepackages.exists()
+
+        cross_build_files = xbuildenv_root / "site-packages-extras"
+        for file in cross_build_files.iterdir():
+            assert (hostsitepackages / file.name).exists()
+
     def test_create_package_index(self, tmp_path, dummy_xbuildenv_url):
         manager = CrossBuildEnvManager(tmp_path)
 
@@ -364,6 +399,31 @@ def test__init_xbuild_env(
         build_env._init_xbuild_env(xbuildenv_path=tmp_path)
         assert manager.current_version >= "0.27.7"
 
+    def test_ensure_cross_build_packages_installed_idempotent(
+        self, tmp_path, dummy_xbuildenv_url, monkeypatch_subprocess_run_pip
+    ):
+        pip_called_with = monkeypatch_subprocess_run_pip
+        manager = CrossBuildEnvManager(tmp_path)
+
+        # Lazy install path: no cross-build packages installed yet
+        manager.install(
+            version=None,
+            url=dummy_xbuildenv_url,
+            skip_install_cross_build_packages=True,
+        )
+        assert pip_called_with == []
+
+        # First ensure installs once
+        manager.ensure_cross_build_packages_installed()
+        assert len(pip_called_with) == 9
+
+        # Second ensure is a no-op
+        manager.ensure_cross_build_packages_installed()
+        assert len(pip_called_with) == 9
+
+        marker = manager.symlink_dir.resolve() / ".cross-build-packages-installed"
+        assert marker.exists()
+
 
 @pytest.mark.parametrize(
     "url, version",
diff --git a/pyodide_build/xbuildenv.py b/pyodide_build/xbuildenv.py
index eca1d40c..ed14cea0 100644
--- a/pyodide_build/xbuildenv.py
+++ b/pyodide_build/xbuildenv.py
@@ -2,11 +2,12 @@
 import os
 import shutil
 import subprocess
+import sys
 from pathlib import Path
 
 from pyodide_lock import PyodideLockSpec
 
-from pyodide_build import build_env
+from pyodide_build import build_env, uv_helper
 from pyodide_build.common import download_and_unpack_archive, remove_readonly
 from pyodide_build.create_package_index import create_package_index
 from pyodide_build.logger import logger
@@ -19,6 +20,7 @@
 CDN_BASE = "https://cdn.jsdelivr.net/pyodide/v{version}/full/"
 PYTHON_VERSION_MARKER_FILE = ".build-python-version"
 EMSCRIPTEN_VERSION_MARKER_FILE = ".emscripten-version"
+CROSS_BUILD_PACKAGES_MARKER_FILE = ".cross-build-packages-installed"
 
 
 class CrossBuildEnvManager:
@@ -81,6 +83,44 @@ def _path_for_version(self, version: str) -> Path:
         """Returns the path to the xbuildenv for the given version."""
         return self.env_dir / version
 
+    def _cross_build_packages_marker_path(self, version_path: Path) -> Path:
+        """
+        Return the marker file path used to record cross-build package installation.
+
+        Parameters
+        ----------
+        version_path
+            Path to a concrete xbuildenv version directory (for example, `.../`).
+        """
+        return version_path / CROSS_BUILD_PACKAGES_MARKER_FILE
+
+    def ensure_cross_build_packages_installed(self) -> None:
+        """
+        Install cross-build packages for the active xbuildenv only when needed.
+
+        This method is idempotent: if the marker file is already present, it does
+        nothing. Otherwise it installs packages into HOSTSITEPACKAGES and writes
+        the marker on success.
+
+        Raises
+        ------
+        ValueError
+            If no active xbuildenv is selected.
+        RuntimeError
+            If package installation fails.
+        """
+        version_path = self.symlink_dir.resolve()
+        marker = self._cross_build_packages_marker_path(version_path)
+        if marker.exists():
+            return
+
+        xbuildenv_root = version_path / "xbuildenv"
+        xbuildenv_pyodide_root = xbuildenv_root / "pyodide-root"
+
+        logger.info("Installing cross-build packages for %s", version_path.name)
+        self._install_cross_build_packages(xbuildenv_root, xbuildenv_pyodide_root)
+        marker.touch()
+
     def list_versions(self) -> list[str]:
         """
         List the downloaded xbuildenv versions.
@@ -156,7 +196,7 @@ def install(
             as the current version of pyodide-build, make sure that the cross-build
             environment is compatible with the current version of Pyodide.
         skip_install_cross_build_packages
-            Deprecated, no longer used.
+            If True, skip installing the cross-build packages. This is mostly for testing purposes.
         force_install
             If True, force the installation even if the cross-build environment is not compatible
 
@@ -165,15 +205,6 @@ def install(
         Path to the root directory for the cross-build environment.
         """
 
-        if not skip_install_cross_build_packages:
-            import warnings
-
-            warnings.warn(
-                "skip_install_cross_build_packages is deprecated and no longer has any effect.",
-                DeprecationWarning,
-                stacklevel=2,
-            )
-
         if url and version:
             raise ValueError("Cannot specify both version and url")
 
@@ -222,6 +253,12 @@ def install(
                     "Installing Pyodide cross-build environment to %s", download_path
                 )
 
+                if not skip_install_cross_build_packages:
+                    self._install_cross_build_packages(
+                        xbuildenv_root, xbuildenv_pyodide_root
+                    )
+                    self._cross_build_packages_marker_path(download_path).touch()
+
                 if not url:
                     # If installed from url, skip creating the PyPI index (version is not known)
                     self._create_package_index(xbuildenv_pyodide_root, version)
@@ -277,6 +314,64 @@ def _get_default_xbuildenv_url(self) -> str:
         """
         return build_env.get_host_build_flag("DEFAULT_CROSS_BUILD_ENV_URL")
 
+    def _install_cross_build_packages(
+        self, xbuildenv_root: Path, xbuildenv_pyodide_root: Path
+    ) -> None:
+        """
+        Install package that are used in the cross-build environment.
+
+        Parameters
+        ----------
+        xbuildenv_root
+            Path to the xbuildenv directory.
+        xbuildenv_pyodide_root
+            Path to the pyodide-root directory inside the xbuildenv directory.
+        """
+        host_site_packages = self._host_site_packages_dir(xbuildenv_pyodide_root)
+        host_site_packages.mkdir(exist_ok=True, parents=True)
+
+        install_prefix = (
+            [
+                uv_helper.find_uv_bin(),
+                "pip",
+                "install",
+            ]
+            if uv_helper.should_use_uv()
+            else [
+                sys.executable,
+                "-m",
+                "pip",
+                "install",
+                "--no-user",
+            ]
+        )
+
+        result = subprocess.run(
+            [
+                *install_prefix,
+                "-r",
+                str(xbuildenv_root / "requirements.txt"),
+                "--target",
+                str(host_site_packages),
+            ],
+            capture_output=True,
+            encoding="utf8",
+            check=False,
+        )
+
+        if result.returncode != 0:
+            raise RuntimeError(
+                f"Failed to install cross-build packages: {result.stderr}"
+            )
+
+        # Copy the site-packages-extras (coming from the cross-build-files meta.yaml
+        # key) over the site-packages directory with the newly installed packages.
+        shutil.copytree(
+            xbuildenv_root / "site-packages-extras",
+            host_site_packages,
+            dirs_exist_ok=True,
+        )
+
     def _host_site_packages_dir(
         self, xbuildenv_pyodide_root: Path | None = None
     ) -> Path:

From a97c864a91fb4a3a71e4663c6402cd612b1b69e8 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sun, 7 Jun 2026 23:58:38 +0530
Subject: [PATCH 43/71] Restructure and add lazy tests back

---
 pyodide_build/tests/test_pypabuild.py | 36 +++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py
index 838e8709..c35ffadf 100644
--- a/pyodide_build/tests/test_pypabuild.py
+++ b/pyodide_build/tests/test_pypabuild.py
@@ -142,6 +142,42 @@ def test_get_build_env(tmp_path, dummy_xbuildenv):
         assert "exports" in wasmcross_args
 
 
+def test_install_reqs_triggers_lazy_install(tmp_path, monkeypatch):
+    called = {"count": 0}
+
+    class DummyManager:
+        def ensure_cross_build_packages_installed(self):
+            called["count"] += 1
+
+    monkeypatch.setattr(pypabuild, "in_xbuildenv", lambda: True)
+    monkeypatch.setattr(pypabuild, "get_current_xbuildenv_manager", DummyManager)
+    monkeypatch.setattr(pypabuild, "get_unisolated_packages", lambda: {"numpy": "1.0"})
+    monkeypatch.setattr(pypabuild, "_install_cross_build_files", lambda *a, **kw: None)
+
+    env = MockIsolatedEnv(tmp_path)
+    pypabuild.install_reqs({}, env, {"numpy>=1.0"})
+
+    assert called["count"] == 1
+
+
+def test_install_reqs_skips_lazy_install_when_not_unisolated(tmp_path, monkeypatch):
+    called = {"count": 0}
+
+    class DummyManager:
+        def ensure_cross_build_packages_installed(self):
+            called["count"] += 1
+
+    monkeypatch.setattr(pypabuild, "in_xbuildenv", lambda: True)
+    monkeypatch.setattr(pypabuild, "get_current_xbuildenv_manager", DummyManager)
+    monkeypatch.setattr(pypabuild, "get_unisolated_packages", lambda: {"numpy": "1.0"})
+    monkeypatch.setattr(pypabuild, "_install_cross_build_files", lambda *a, **kw: None)
+
+    env = MockIsolatedEnv(tmp_path)
+    pypabuild.install_reqs({}, env, {"foo>=1.0"})
+
+    assert called["count"] == 0
+
+
 def _make_cpe(
     stdout: str | bytes | None = None, stderr: str | bytes | None = None
 ) -> subprocess.CalledProcessError:

From a0f54206e9ee7ebfc278c5beaa050734a6d8d1bc Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Mon, 8 Jun 2026 03:31:00 +0530
Subject: [PATCH 44/71] Discard changes to pyodide_build/xbuildenv.py

---
 pyodide_build/xbuildenv.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyodide_build/xbuildenv.py b/pyodide_build/xbuildenv.py
index ed14cea0..7683b407 100644
--- a/pyodide_build/xbuildenv.py
+++ b/pyodide_build/xbuildenv.py
@@ -19,8 +19,8 @@
 
 CDN_BASE = "https://cdn.jsdelivr.net/pyodide/v{version}/full/"
 PYTHON_VERSION_MARKER_FILE = ".build-python-version"
-EMSCRIPTEN_VERSION_MARKER_FILE = ".emscripten-version"
 CROSS_BUILD_PACKAGES_MARKER_FILE = ".cross-build-packages-installed"
+EMSCRIPTEN_VERSION_MARKER_FILE = ".emscripten-version"
 
 
 class CrossBuildEnvManager:

From 29ef6e850f1111d45612211704e300d639edf81b Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Mon, 8 Jun 2026 04:09:23 +0530
Subject: [PATCH 45/71] Add back existence guard in `get_unisolated_packages`

---
 pyodide_build/build_env.py | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py
index bea2e7dc..d4414ba9 100644
--- a/pyodide_build/build_env.py
+++ b/pyodide_build/build_env.py
@@ -241,16 +241,17 @@ def get_unisolated_packages() -> dict[str, str]:
     if in_xbuildenv():
         unisolated_packages_file = PYODIDE_ROOT / ".." / "requirements.txt"
 
-        for line in unisolated_packages_file.read_text().splitlines():
-            line = line.strip()
-            # The xbuildenv requirements.txt is machine-generated and always
-            # uses pinned name==version entries, but we skip blank lines,
-            # comments, and any non-pinned specs just in case. Shouldn't
-            # really happen though.
-            if not line or line.startswith("#") or "==" not in line:
-                continue
-            name, version = line.split("==", 1)
-            unisolated_packages[name] = version
+        if unisolated_packages_file.exists():
+            for line in unisolated_packages_file.read_text().splitlines():
+                line = line.strip()
+                # The xbuildenv requirements.txt is machine-generated and always
+                # uses pinned name==version entries, but we skip blank lines,
+                # comments, and any non-pinned specs just in case. Shouldn't
+                # really happen though.
+                if not line or line.startswith("#") or "==" not in line:
+                    continue
+                name, version = line.split("==", 1)
+                unisolated_packages[name] = version
     else:
         from pyodide_build.recipe.loader import load_all_recipes
 

From a95de42aa03ddd34fcc9d7b4610fd70f7fa49aa8 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Mon, 8 Jun 2026 04:10:11 +0530
Subject: [PATCH 46/71] Fix case-sensitivity issue in
 `_replace_unisolated_packages`

---
 pyodide_build/pypabuild.py | 34 ++++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 085063a0..0aacfd39 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -13,6 +13,7 @@
 from build import BuildBackendException, ConfigSettingsType, ProjectBuilder
 from build.env import DefaultIsolatedEnv
 from packaging.requirements import Requirement
+from packaging.utils import canonicalize_name
 
 from pyodide_build import _f2c_fixes, common, pywasmcross, uv_helper
 from pyodide_build.build_env import (
@@ -130,24 +131,29 @@ def _replace_unisolated_packages(
     -------
     A tuple of (the filtered set of requirements, the set of unisolated requirements)
     """
+    canonical_unisolated = {
+        canonicalize_name(name): (name, version)
+        for name, version in unisolated_packages.items()
+    }
+
     new_reqs = reqs.copy()
     unisolated: set[str] = set()
     for reqstr in list(reqs):
         req = Requirement(reqstr)
-        for name, version in unisolated_packages.items():
-            if req.name == name:
-                # TODO: find a better way to handle this case
-                if not req.specifier.contains(version):
-                    warnings.warn(
-                        f"Found build dependency {req} but the only supported "
-                        f"cross-build version is {name}=={version}; "
-                        f"using {name}=={version} instead.",
-                        stacklevel=2,
-                    )
-                new_reqs.discard(reqstr)
-                new_reqs.add(f"{name}=={version}")
-                unisolated.add(name)
-                break
+        match = canonical_unisolated.get(canonicalize_name(req.name))
+        if match is not None:
+            name, version = match
+            # TODO: find a better way to handle this case
+            if not req.specifier.contains(version):
+                warnings.warn(
+                    f"Found build dependency {req} but the only supported "
+                    f"cross-build version is {name}=={version}; "
+                    f"using {name}=={version} instead.",
+                    stacklevel=2,
+                )
+            new_reqs.discard(reqstr)
+            new_reqs.add(f"{name}=={version}")
+            unisolated.add(name)
     return new_reqs, unisolated
 
 

From 37bbc6f33bfef0b0db4c90e33b9815c31303f9ca Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Mon, 8 Jun 2026 04:11:35 +0530
Subject: [PATCH 47/71] Rename `symlink_unisolated_packages` to something
 better

---
 pyodide_build/pypabuild.py | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 0aacfd39..9ae82e69 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -98,9 +98,11 @@ def _runner(cmd, cwd=None, extra_environ=None):
     return _runner
 
 
-def symlink_unisolated_packages(
-    env: DefaultIsolatedEnv, reqs: set[str] | None = None
-) -> None:
+def _copy_sysconfigdata_to_isolated_env(env: DefaultIsolatedEnv) -> None:
+    """
+    Copy the sysconfigdata module into the isolated build environment's
+    site-packages so that builds can pick up Pyodide's build configuration.
+    """
     pyversion = get_pyversion()
     site_packages_path = f"lib/{pyversion}/site-packages"
     env_site_packages = Path(env.path) / site_packages_path
@@ -249,7 +251,7 @@ def _build_in_isolated_env(
         )
 
         # first install the build dependencies
-        symlink_unisolated_packages(env, builder.build_system_requires)
+        _copy_sysconfigdata_to_isolated_env(env)
         install_reqs(build_env, env, builder.build_system_requires)
         build_reqs: set[str] | None = None
         try:

From c0a3603861916545f6557c492b1f1179a2ff1f56 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Mon, 8 Jun 2026 04:14:37 +0530
Subject: [PATCH 48/71] Use `shutil.copytree` for cross-build file copying

---
 pyodide_build/build_env.py | 17 +++++++----------
 pyodide_build/pypabuild.py |  9 ++++-----
 2 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py
index d4414ba9..9ec610c3 100644
--- a/pyodide_build/build_env.py
+++ b/pyodide_build/build_env.py
@@ -264,9 +264,10 @@ def get_unisolated_packages() -> dict[str, str]:
     return unisolated_packages
 
 
-def get_unisolated_files(package_name: str) -> tuple[Path, list[str]]:
+def get_unisolated_files(package_name: str) -> Path:
     """
-    Get an unisolated package's cross-build files.
+    Get the directory containing an unisolated package's cross-build files
+    (such as headers, .a libs, .pxd files, and so on).
 
     Parameters
     ----------
@@ -275,10 +276,9 @@ def get_unisolated_files(package_name: str) -> tuple[Path, list[str]]:
 
     Returns
     -------
-    A tuple of (base_dir, relative_paths) where base_dir is the root directory
-    containing all unisolated packages (e.g. site-packages-extras) and
-    relative_paths is the list of file paths for this package relative to base_dir.
-
+    The directory containing the package's cross-build files, relative to
+    which they should be laid out in site-packages. The directory may not
+    exist if the package has no cross-build files.
     """
     PYODIDE_ROOT = get_pyodide_root()
 
@@ -288,10 +288,7 @@ def get_unisolated_files(package_name: str) -> tuple[Path, list[str]]:
     else:
         libdir = Path(get_hostsitepackages())
 
-    package_dir = libdir / package_name
-    return libdir, [
-        str(f.relative_to(libdir)) for f in package_dir.rglob("*") if f.is_file()
-    ]
+    return libdir / package_name
 
 
 def platform() -> str:
diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 9ae82e69..a64b1a2e 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -177,11 +177,10 @@ def _install_cross_build_files(venv_path: str, unisolated: set[str]) -> None:
     _, _, purelib = _find_executable_and_scripts(venv_path)
     sitepackagesdir = Path(purelib)
     for name in unisolated:
-        base, files = get_unisolated_files(name)
-        for rel in files:
-            dest = sitepackagesdir / rel
-            dest.parent.mkdir(parents=True, exist_ok=True)
-            shutil.copy(base / rel, dest)
+        package_dir = get_unisolated_files(name)
+        if not package_dir.is_dir():
+            continue
+        shutil.copytree(package_dir, sitepackagesdir / name, dirs_exist_ok=True)
 
 
 def remove_avoided_requirements(

From afdbe683b431bad5dfc6ceaf12bf2f5d3cd286e1 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Mon, 8 Jun 2026 04:16:12 +0530
Subject: [PATCH 49/71] Add tests for getting unisolated packages

---
 pyodide_build/tests/test_build_env.py | 41 +++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/pyodide_build/tests/test_build_env.py b/pyodide_build/tests/test_build_env.py
index 983fb676..5abb6063 100644
--- a/pyodide_build/tests/test_build_env.py
+++ b/pyodide_build/tests/test_build_env.py
@@ -59,6 +59,47 @@ def test_get_pyodide_root_pyodide_root_already_set(
     def test_in_xbuildenv(self, dummy_xbuildenv, reset_env_vars, reset_cache):
         assert build_env.in_xbuildenv()
 
+    def test_get_unisolated_packages(
+        self, dummy_xbuildenv, reset_env_vars, reset_cache
+    ):
+        manager = CrossBuildEnvManager(dummy_xbuildenv / common.xbuildenv_dirname())
+        requirements_file = manager.pyodide_root / ".." / "requirements.txt"
+
+        expected = {}
+        for line in requirements_file.read_text().splitlines():
+            name, version = line.strip().split("==", 1)
+            expected[name] = version
+
+        assert expected
+        assert build_env.get_unisolated_packages() == expected
+
+    def test_get_unisolated_packages_no_requirements_file(
+        self, dummy_xbuildenv, reset_env_vars, reset_cache
+    ):
+        manager = CrossBuildEnvManager(dummy_xbuildenv / common.xbuildenv_dirname())
+        requirements_file = manager.pyodide_root / ".." / "requirements.txt"
+        requirements_file.unlink()
+
+        assert build_env.get_unisolated_packages() == {}
+
+    def test_get_unisolated_files(self, dummy_xbuildenv, reset_env_vars, reset_cache):
+        manager = CrossBuildEnvManager(dummy_xbuildenv / common.xbuildenv_dirname())
+        site_packages_extras = manager.pyodide_root / ".." / "site-packages-extras"
+
+        for name in ("numpy", "scipy"):
+            package_dir = build_env.get_unisolated_files(name)
+            assert package_dir == site_packages_extras / name
+            assert package_dir.is_dir()
+            assert any(package_dir.rglob("*"))
+
+    def test_get_unisolated_files_no_cross_build_files(
+        self, dummy_xbuildenv, reset_env_vars, reset_cache
+    ):
+        # cffi is an unisolated package but has no cross-build files in the
+        # dummy xbuildenv, so the directory simply doesn't exist
+        package_dir = build_env.get_unisolated_files("cffi")
+        assert not package_dir.exists()
+
     def test_get_build_environment_vars(
         self, dummy_xbuildenv, reset_env_vars, reset_cache
     ):

From 9d89aa7fad00c4c82cc89c796e7b90d4db09db53 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Mon, 8 Jun 2026 04:16:52 +0530
Subject: [PATCH 50/71] Tests for unisolated package name normalisation

---
 pyodide_build/tests/test_pypabuild.py | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py
index c35ffadf..52c5c12c 100644
--- a/pyodide_build/tests/test_pypabuild.py
+++ b/pyodide_build/tests/test_pypabuild.py
@@ -45,6 +45,20 @@ def test_replace_unisolated_packages():
     assert replaced == {"foo", "bar", "baz"}
 
 
+def test_replace_unisolated_packages_normalizes_names():
+    requires = {"NumPy>=1.20", "Ruamel-YAML"}
+    unisolated = {
+        "numpy": "2.0.3",
+        "ruamel.yaml": "0.18.6",
+    }
+
+    new_requires, replaced = pypabuild._replace_unisolated_packages(
+        requires, unisolated
+    )
+    assert new_requires == {"numpy==2.0.3", "ruamel.yaml==0.18.6"}
+    assert replaced == {"numpy", "ruamel.yaml"}
+
+
 def test_replace_unisolated_packages_version_mismatch():
     """
     FIXME: This is not an ideal behavior, but for now we just ignore the version mismatch.

From 4fdbf9c5e21f610e5085c4b12e8845737e2f670d Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Mon, 8 Jun 2026 04:18:38 +0530
Subject: [PATCH 51/71] Tests for cross-build file installation

---
 pyodide_build/tests/test_pypabuild.py | 62 +++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)

diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py
index 52c5c12c..6f90e55b 100644
--- a/pyodide_build/tests/test_pypabuild.py
+++ b/pyodide_build/tests/test_pypabuild.py
@@ -192,6 +192,68 @@ def ensure_cross_build_packages_installed(self):
     assert called["count"] == 0
 
 
+def test_install_cross_build_files(tmp_path, monkeypatch):
+    purelib = tmp_path / "venv" / "lib" / "site-packages"
+    purelib.mkdir(parents=True)
+
+    extras = tmp_path / "site-packages-extras"
+    numpy_header = extras / "numpy" / "_core" / "include" / "numpy" / "ndarrayobject.h"
+    numpy_header.parent.mkdir(parents=True)
+    numpy_header.write_text("// header")
+    scipy_pxd = extras / "scipy" / "linalg" / "cython_blas.pxd"
+    scipy_pxd.parent.mkdir(parents=True)
+    scipy_pxd.write_text("# pxd")
+
+    monkeypatch.setattr(
+        pypabuild,
+        "_find_executable_and_scripts",
+        lambda venv_path: ("python", "scripts", str(purelib)),
+    )
+    monkeypatch.setattr(pypabuild, "get_unisolated_files", lambda name: extras / name)
+
+    pypabuild._install_cross_build_files(str(tmp_path / "venv"), {"numpy", "scipy"})
+
+    assert (
+        purelib / "numpy" / "_core" / "include" / "numpy" / "ndarrayobject.h"
+    ).read_text() == "// header"
+    assert (purelib / "scipy" / "linalg" / "cython_blas.pxd").read_text() == "# pxd"
+
+
+def test_install_cross_build_files_skips_packages_without_cross_build_files(
+    tmp_path, monkeypatch
+):
+    purelib = tmp_path / "venv" / "lib" / "site-packages"
+    purelib.mkdir(parents=True)
+
+    monkeypatch.setattr(
+        pypabuild,
+        "_find_executable_and_scripts",
+        lambda venv_path: ("python", "scripts", str(purelib)),
+    )
+    # cffi has no cross-build files, so its directory does not exist
+    monkeypatch.setattr(
+        pypabuild,
+        "get_unisolated_files",
+        lambda name: tmp_path / "does-not-exist" / name,
+    )
+
+    pypabuild._install_cross_build_files(str(tmp_path / "venv"), {"cffi"})
+
+    assert list(purelib.iterdir()) == []
+
+
+def test_install_cross_build_files_skips_when_no_unisolated_packages(
+    tmp_path, monkeypatch
+):
+    def _unexpected_call(*args, **kwargs):
+        raise AssertionError("should not be called when there are no unisolated reqs")
+
+    monkeypatch.setattr(pypabuild, "_find_executable_and_scripts", _unexpected_call)
+    monkeypatch.setattr(pypabuild, "get_unisolated_files", _unexpected_call)
+
+    pypabuild._install_cross_build_files(str(tmp_path / "venv"), set())
+
+
 def _make_cpe(
     stdout: str | bytes | None = None, stderr: str | bytes | None = None
 ) -> subprocess.CalledProcessError:

From 905925b30713f5d9603dab7d85e8226c5e2d70cc Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 27 Jun 2026 05:56:07 +0530
Subject: [PATCH 52/71] Drop unnecessary list conversion

Co-Authored-By: Gyeongjae Choi 
---
 pyodide_build/pypabuild.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index a64b1a2e..851793da 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -140,7 +140,7 @@ def _replace_unisolated_packages(
 
     new_reqs = reqs.copy()
     unisolated: set[str] = set()
-    for reqstr in list(reqs):
+    for reqstr in reqs:
         req = Requirement(reqstr)
         match = canonical_unisolated.get(canonicalize_name(req.name))
         if match is not None:

From 44e6da01bc0006cb4a4296d3e6129cb4fa06d5b3 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 27 Jun 2026 05:56:37 +0530
Subject: [PATCH 53/71] Invert condition for matched packages

Co-Authored-By: Gyeongjae Choi 
---
 pyodide_build/pypabuild.py | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index 851793da..d2ec6a16 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -143,19 +143,20 @@ def _replace_unisolated_packages(
     for reqstr in reqs:
         req = Requirement(reqstr)
         match = canonical_unisolated.get(canonicalize_name(req.name))
-        if match is not None:
-            name, version = match
-            # TODO: find a better way to handle this case
-            if not req.specifier.contains(version):
-                warnings.warn(
-                    f"Found build dependency {req} but the only supported "
-                    f"cross-build version is {name}=={version}; "
-                    f"using {name}=={version} instead.",
-                    stacklevel=2,
-                )
-            new_reqs.discard(reqstr)
-            new_reqs.add(f"{name}=={version}")
-            unisolated.add(name)
+        if match is None:
+            continue
+        name, version = match
+        # TODO: find a better way to handle this case
+        if not req.specifier.contains(version):
+            warnings.warn(
+                f"Found build dependency {req} but the only supported "
+                f"cross-build version is {name}=={version}; "
+                f"using {name}=={version} instead.",
+                stacklevel=2,
+            )
+        new_reqs.discard(reqstr)
+        new_reqs.add(f"{name}=={version}")
+        unisolated.add(name)
     return new_reqs, unisolated
 
 

From 0772d469271e4b8adc405f5a4e79f7560946e29d Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 27 Jun 2026 05:57:39 +0530
Subject: [PATCH 54/71] Rename `get_unisolated_files` to
 `get_cross_build_files_dir`

Co-Authored-By: Gyeongjae Choi 
---
 pyodide_build/build_env.py            | 2 +-
 pyodide_build/pypabuild.py            | 4 ++--
 pyodide_build/tests/test_build_env.py | 4 +++-
 pyodide_build/tests/test_pypabuild.py | 8 +++++---
 4 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py
index 9ec610c3..ab2b9429 100644
--- a/pyodide_build/build_env.py
+++ b/pyodide_build/build_env.py
@@ -264,7 +264,7 @@ def get_unisolated_packages() -> dict[str, str]:
     return unisolated_packages
 
 
-def get_unisolated_files(package_name: str) -> Path:
+def get_cross_build_files_dir(package_name: str) -> Path:
     """
     Get the directory containing an unisolated package's cross-build files
     (such as headers, .a libs, .pxd files, and so on).
diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py
index d2ec6a16..7e3e5484 100644
--- a/pyodide_build/pypabuild.py
+++ b/pyodide_build/pypabuild.py
@@ -18,10 +18,10 @@
 from pyodide_build import _f2c_fixes, common, pywasmcross, uv_helper
 from pyodide_build.build_env import (
     get_build_flag,
+    get_cross_build_files_dir,
     get_current_xbuildenv_manager,
     get_host_build_flag,
     get_pyversion,
-    get_unisolated_files,
     get_unisolated_packages,
     in_xbuildenv,
     platform,
@@ -178,7 +178,7 @@ def _install_cross_build_files(venv_path: str, unisolated: set[str]) -> None:
     _, _, purelib = _find_executable_and_scripts(venv_path)
     sitepackagesdir = Path(purelib)
     for name in unisolated:
-        package_dir = get_unisolated_files(name)
+        package_dir = get_cross_build_files_dir(name)
         if not package_dir.is_dir():
             continue
         shutil.copytree(package_dir, sitepackagesdir / name, dirs_exist_ok=True)
diff --git a/pyodide_build/tests/test_build_env.py b/pyodide_build/tests/test_build_env.py
index 5abb6063..58156ddd 100644
--- a/pyodide_build/tests/test_build_env.py
+++ b/pyodide_build/tests/test_build_env.py
@@ -82,7 +82,9 @@ def test_get_unisolated_packages_no_requirements_file(
 
         assert build_env.get_unisolated_packages() == {}
 
-    def test_get_unisolated_files(self, dummy_xbuildenv, reset_env_vars, reset_cache):
+    def test_get_cross_build_files_dir(
+        self, dummy_xbuildenv, reset_env_vars, reset_cache
+    ):
         manager = CrossBuildEnvManager(dummy_xbuildenv / common.xbuildenv_dirname())
         site_packages_extras = manager.pyodide_root / ".." / "site-packages-extras"
 
diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py
index 6f90e55b..ac221f09 100644
--- a/pyodide_build/tests/test_pypabuild.py
+++ b/pyodide_build/tests/test_pypabuild.py
@@ -209,7 +209,9 @@ def test_install_cross_build_files(tmp_path, monkeypatch):
         "_find_executable_and_scripts",
         lambda venv_path: ("python", "scripts", str(purelib)),
     )
-    monkeypatch.setattr(pypabuild, "get_unisolated_files", lambda name: extras / name)
+    monkeypatch.setattr(
+        pypabuild, "get_cross_build_files_dir", lambda name: extras / name
+    )
 
     pypabuild._install_cross_build_files(str(tmp_path / "venv"), {"numpy", "scipy"})
 
@@ -233,7 +235,7 @@ def test_install_cross_build_files_skips_packages_without_cross_build_files(
     # cffi has no cross-build files, so its directory does not exist
     monkeypatch.setattr(
         pypabuild,
-        "get_unisolated_files",
+        "get_cross_build_files_dir",
         lambda name: tmp_path / "does-not-exist" / name,
     )
 
@@ -249,7 +251,7 @@ def _unexpected_call(*args, **kwargs):
         raise AssertionError("should not be called when there are no unisolated reqs")
 
     monkeypatch.setattr(pypabuild, "_find_executable_and_scripts", _unexpected_call)
-    monkeypatch.setattr(pypabuild, "get_unisolated_files", _unexpected_call)
+    monkeypatch.setattr(pypabuild, "get_cross_build_files_dir", _unexpected_call)
 
     pypabuild._install_cross_build_files(str(tmp_path / "venv"), set())
 

From 981b099769903f2efc969fb41c6002f9a799434a Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 27 Jun 2026 05:59:39 +0530
Subject: [PATCH 55/71] Simplify CHANGELOG entry

Co-Authored-By: Gyeongjae Choi 
---
 CHANGELOG.md | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 70ce3f7f..70c2dd09 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,18 +27,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Changed
 
-- Unisolated packages are now installed into the isolated build environment via
-  pip, with their cross-build files replaced by WASM-compatible versions from
-  the cross-build environment. This makes build-time scripts exposed by these
-  packages available on `PATH` during the build process.
+- Fixed build-time scripts of unisolated packages (like `f2py` and
+  `numpy-config` from NumPy) not being available on `PATH` during builds.
   [#21](https://github.com/pyodide/pyodide-build/pull/21)
 
 - `oldest-supported-numpy` is no longer silently ignored when encountered as a
-  build-time dependency. It will now be installed as any other package. Since
+  build-time dependency. It will now be installed like any other package. Since
   `oldest-supported-numpy` is deprecated since NumPy 2.0, packages that still
-  list it should migrate to a direct `numpy` dependency. If you need to ignore
-  it (or any other build requirement), set it via
-  `pyodide config set ignored_build_requirements "patchelf oldest-supported-numpy"`
+  list it should migrate to a direct `numpy` dependency.
   [#21](https://github.com/pyodide/pyodide-build/pull/21)
 
 ## [0.34.4] - 2026/05/15

From e523091482490a5c19cc3948247fbb6e43e5f881 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 27 Jun 2026 06:08:02 +0530
Subject: [PATCH 56/71] Simplify tests for cross-build files checking

Co-Authored-By: Gyeongjae Choi 
---
 pyodide_build/tests/test_build_env.py | 19 +++++++++++--------
 pyodide_build/tests/test_pypabuild.py |  3 +--
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/pyodide_build/tests/test_build_env.py b/pyodide_build/tests/test_build_env.py
index 58156ddd..8204a8da 100644
--- a/pyodide_build/tests/test_build_env.py
+++ b/pyodide_build/tests/test_build_env.py
@@ -88,18 +88,21 @@ def test_get_cross_build_files_dir(
         manager = CrossBuildEnvManager(dummy_xbuildenv / common.xbuildenv_dirname())
         site_packages_extras = manager.pyodide_root / ".." / "site-packages-extras"
 
-        for name in ("numpy", "scipy"):
-            package_dir = build_env.get_unisolated_files(name)
-            assert package_dir == site_packages_extras / name
-            assert package_dir.is_dir()
+        # Check every package that actually has a directory in site-packages-extras
+        found_any = False
+        for subdir in site_packages_extras.iterdir():
+            if not subdir.is_dir():
+                continue
+            found_any = True
+            package_dir = build_env.get_cross_build_files_dir(subdir.name)
+            assert package_dir == subdir
             assert any(package_dir.rglob("*"))
+        assert found_any
 
-    def test_get_unisolated_files_no_cross_build_files(
+    def test_get_cross_build_files_dir_missing_package(
         self, dummy_xbuildenv, reset_env_vars, reset_cache
     ):
-        # cffi is an unisolated package but has no cross-build files in the
-        # dummy xbuildenv, so the directory simply doesn't exist
-        package_dir = build_env.get_unisolated_files("cffi")
+        package_dir = build_env.get_cross_build_files_dir("no-such-package")
         assert not package_dir.exists()
 
     def test_get_build_environment_vars(
diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py
index ac221f09..c321fb1a 100644
--- a/pyodide_build/tests/test_pypabuild.py
+++ b/pyodide_build/tests/test_pypabuild.py
@@ -232,14 +232,13 @@ def test_install_cross_build_files_skips_packages_without_cross_build_files(
         "_find_executable_and_scripts",
         lambda venv_path: ("python", "scripts", str(purelib)),
     )
-    # cffi has no cross-build files, so its directory does not exist
     monkeypatch.setattr(
         pypabuild,
         "get_cross_build_files_dir",
         lambda name: tmp_path / "does-not-exist" / name,
     )
 
-    pypabuild._install_cross_build_files(str(tmp_path / "venv"), {"cffi"})
+    pypabuild._install_cross_build_files(str(tmp_path / "venv"), {"some-package"})
 
     assert list(purelib.iterdir()) == []
 

From a1ea4be0ce65354947fa985cf4965a5458dee858 Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 27 Jun 2026 06:20:35 +0530
Subject: [PATCH 57/71] Simplify Fortran package recipe

---
 integration_tests/recipes/README.md           |  1 +
 .../recipes/f2py-example/meta.yaml            | 34 -------------
 .../source/f2py_example/__init__.py           |  3 --
 .../recipes/f2py-example/source/meson.build   | 48 -------------------
 .../f2py-example/source/src/fibonacci.f       | 18 -------
 .../recipes/numpy-scripts-example/meta.yaml   | 23 +++++++++
 .../numpy-scripts-example/source/meson.build  | 32 +++++++++++++
 .../source/numpy_scripts_example/__init__.py  |  3 ++
 .../source/numpy_scripts_example/_add.c       | 28 +++++++++++
 .../source/pyproject.toml                     |  2 +-
 10 files changed, 88 insertions(+), 104 deletions(-)
 delete mode 100644 integration_tests/recipes/f2py-example/meta.yaml
 delete mode 100644 integration_tests/recipes/f2py-example/source/f2py_example/__init__.py
 delete mode 100644 integration_tests/recipes/f2py-example/source/meson.build
 delete mode 100644 integration_tests/recipes/f2py-example/source/src/fibonacci.f
 create mode 100644 integration_tests/recipes/numpy-scripts-example/meta.yaml
 create mode 100644 integration_tests/recipes/numpy-scripts-example/source/meson.build
 create mode 100644 integration_tests/recipes/numpy-scripts-example/source/numpy_scripts_example/__init__.py
 create mode 100644 integration_tests/recipes/numpy-scripts-example/source/numpy_scripts_example/_add.c
 rename integration_tests/recipes/{f2py-example => numpy-scripts-example}/source/pyproject.toml (83%)

diff --git a/integration_tests/recipes/README.md b/integration_tests/recipes/README.md
index c245e798..dc5d0c57 100644
--- a/integration_tests/recipes/README.md
+++ b/integration_tests/recipes/README.md
@@ -11,6 +11,7 @@ This directory contains a few curated recipes to test the build process of pyodi
 - `pydoc_data`: Unvendored cpython module
 - `boost-histogram``: Tests scikit-build-core and cmake build system.
 - `colorama`: Uses prebuilt wheel as source to check test file unvendoring capabilities.
+- `numpy-scripts-example`: Tests that unisolated package scripts (say, `f2py` or `numpy-config` from NumPy as a build dependency) are available on PATH during builds.
 
 ### For maintainers
 
diff --git a/integration_tests/recipes/f2py-example/meta.yaml b/integration_tests/recipes/f2py-example/meta.yaml
deleted file mode 100644
index 19900e14..00000000
--- a/integration_tests/recipes/f2py-example/meta.yaml
+++ /dev/null
@@ -1,34 +0,0 @@
-package:
-  name: f2py-example
-  version: 0.1.0
-  top-level:
-    - f2py_example
-
-source:
-  path: source
-
-build:
-  cflags: |
-    -I$(WASM_LIBRARY_DIR)/include
-  script: |
-    git clone https://github.com/hoodmane/f2c.git --depth 1
-    (cd f2c/src && cp makefile.u makefile && sed -i "s/gram.c:/gram.c1:/" makefile && make)
-    export F2C_PATH=$(pwd)/f2c/src/f2c
-    cp f2c/f2c.h ${WASM_LIBRARY_DIR}/include/f2c.h
-
-requirements:
-  host:
-    - numpy
-  run:
-    - numpy
-  executable:
-    - gfortran
-
-about:
-  home: https://github.com/pyodide/pyodide-build
-  summary: Minimal Fortran/f2py integration test (Fibonacci, loosely based on github.com/larsbuntemeyer/pyfort)
-  license: MIT
-
-extra:
-  recipe-maintainers:
-    - agriyakhetarpal
diff --git a/integration_tests/recipes/f2py-example/source/f2py_example/__init__.py b/integration_tests/recipes/f2py-example/source/f2py_example/__init__.py
deleted file mode 100644
index b454c205..00000000
--- a/integration_tests/recipes/f2py-example/source/f2py_example/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from .fib import fib
-
-__all__ = ["fib"]
diff --git a/integration_tests/recipes/f2py-example/source/meson.build b/integration_tests/recipes/f2py-example/source/meson.build
deleted file mode 100644
index b03ef4f1..00000000
--- a/integration_tests/recipes/f2py-example/source/meson.build
+++ /dev/null
@@ -1,48 +0,0 @@
-project('f2py-example', 'c',
-  version: '0.1.0',
-  license: 'MIT',
-  meson_version: '>= 1.3.0',
-  default_options: [
-    'buildtype=debugoptimized',
-    'c_args=-Wno-unused-function -Wno-conversion -Wno-misleading-indentation -Wno-incompatible-pointer-types',
-    'fortran_args=-Wno-conversion',
-    'fortran_std=legacy',
-  ],
-)
-
-add_languages('fortran', native: false)
-
-py_mod = import('python')
-py3 = py_mod.find_installation()
-py3_dep = py3.dependency()
-
-numpy_cflags = run_command('numpy-config', '--cflags', check: true).stdout().strip().split()
-
-f2py = find_program('f2py')
-
-incdir_f2py = run_command(py3,
-  ['-c', 'from numpy import f2py; print(f2py.get_include())'],
-  check: true
-).stdout().strip()
-
-fib_source = custom_target('fibmodule.c',
-  input: ['src/fibonacci.f'],
-  output: ['fibmodule.c', 'fib-f2pywrappers.f'],
-  command: [f2py, '@INPUT@', '-m', 'fib', '--lower']
-)
-
-inc_dirs = include_directories(incdir_f2py)
-
-py3.install_sources(['f2py_example/__init__.py'],
-  pure: false,
-  subdir: 'f2py_example')
-
-py3.extension_module('fib',
-  ['src/fibonacci.f', fib_source],
-  incdir_f2py / 'fortranobject.c',
-  include_directories: inc_dirs,
-  c_args: numpy_cflags,
-  dependencies: py3_dep,
-  install: true,
-  subdir: 'f2py_example',
-)
diff --git a/integration_tests/recipes/f2py-example/source/src/fibonacci.f b/integration_tests/recipes/f2py-example/source/src/fibonacci.f
deleted file mode 100644
index e2dd9bff..00000000
--- a/integration_tests/recipes/f2py-example/source/src/fibonacci.f
+++ /dev/null
@@ -1,18 +0,0 @@
-C FILE: FIBONACCI.F
-C Loosely based on the pyfort example by Lars Buntemeyer (MIT licence)
-C https://github.com/larsbuntemeyer/pyfort
-      SUBROUTINE FIB(A, N)
-C     Calculate first N Fibonacci numbers
-      INTEGER N
-      REAL*8 A(N)
-      DO I = 1, N
-         IF (I .EQ. 1) THEN
-            A(I) = 0.0D0
-         ELSEIF (I .EQ. 2) THEN
-            A(I) = 1.0D0
-         ELSE
-            A(I) = A(I-1) + A(I-2)
-         ENDIF
-      ENDDO
-      END
-C END FILE FIBONACCI.F
diff --git a/integration_tests/recipes/numpy-scripts-example/meta.yaml b/integration_tests/recipes/numpy-scripts-example/meta.yaml
new file mode 100644
index 00000000..77aef5b4
--- /dev/null
+++ b/integration_tests/recipes/numpy-scripts-example/meta.yaml
@@ -0,0 +1,23 @@
+package:
+  name: numpy-scripts-example
+  version: 0.1.0
+  top-level:
+    - numpy_scripts_example
+
+source:
+  path: source
+
+requirements:
+  host:
+    - numpy
+  run:
+    - numpy
+
+about:
+  home: https://github.com/pyodide/pyodide-build
+  summary: Minimal integration test that verifies f2py and numpy-config are on PATH during the build
+  license: MIT
+
+extra:
+  recipe-maintainers:
+    - agriyakhetarpal
diff --git a/integration_tests/recipes/numpy-scripts-example/source/meson.build b/integration_tests/recipes/numpy-scripts-example/source/meson.build
new file mode 100644
index 00000000..818da621
--- /dev/null
+++ b/integration_tests/recipes/numpy-scripts-example/source/meson.build
@@ -0,0 +1,32 @@
+project('numpy-scripts-example', 'c',
+  version: '0.1.0',
+  license: 'MIT',
+  meson_version: '>= 1.3.0',
+)
+
+py_mod = import('python')
+py3 = py_mod.find_installation()
+py3_dep = py3.dependency()
+
+# The only point of this recipe is to verify that NumPy's console scripts
+# are discoverable on PATH when it is a build-time dependency.
+f2py = find_program('f2py')
+numpy_cflags = run_command('numpy-config', '--cflags', check: true).stdout().strip().split()
+
+incdir_numpy = run_command(py3,
+  ['-c', 'import numpy; print(numpy.get_include())'],
+  check: true,
+).stdout().strip()
+
+py3.install_sources(['numpy_scripts_example/__init__.py'],
+  pure: false,
+  subdir: 'numpy_scripts_example')
+
+py3.extension_module('_add',
+  'numpy_scripts_example/_add.c',
+  include_directories: incdir_numpy,
+  c_args: numpy_cflags,
+  dependencies: py3_dep,
+  install: true,
+  subdir: 'numpy_scripts_example',
+)
diff --git a/integration_tests/recipes/numpy-scripts-example/source/numpy_scripts_example/__init__.py b/integration_tests/recipes/numpy-scripts-example/source/numpy_scripts_example/__init__.py
new file mode 100644
index 00000000..1be9f4ae
--- /dev/null
+++ b/integration_tests/recipes/numpy-scripts-example/source/numpy_scripts_example/__init__.py
@@ -0,0 +1,3 @@
+from ._add import add
+
+__all__ = ["add"]
diff --git a/integration_tests/recipes/numpy-scripts-example/source/numpy_scripts_example/_add.c b/integration_tests/recipes/numpy-scripts-example/source/numpy_scripts_example/_add.c
new file mode 100644
index 00000000..9daa91e5
--- /dev/null
+++ b/integration_tests/recipes/numpy-scripts-example/source/numpy_scripts_example/_add.c
@@ -0,0 +1,28 @@
+#define PY_SSIZE_T_CLEAN
+#include 
+#include 
+
+static PyObject *
+add(PyObject *self, PyObject *args)
+{
+    double a, b;
+    if (!PyArg_ParseTuple(args, "dd", &a, &b))
+        return NULL;
+    return PyFloat_FromDouble(a + b);
+}
+
+static PyMethodDef methods[] = {
+    {"add", add, METH_VARARGS, "Add two floats."},
+    {NULL, NULL, 0, NULL}
+};
+
+static struct PyModuleDef module = {
+    PyModuleDef_HEAD_INIT, "_add", NULL, -1, methods
+};
+
+PyMODINIT_FUNC
+PyInit__add(void)
+{
+    import_array();
+    return PyModule_Create(&module);
+}
diff --git a/integration_tests/recipes/f2py-example/source/pyproject.toml b/integration_tests/recipes/numpy-scripts-example/source/pyproject.toml
similarity index 83%
rename from integration_tests/recipes/f2py-example/source/pyproject.toml
rename to integration_tests/recipes/numpy-scripts-example/source/pyproject.toml
index 04b25664..70fc583e 100644
--- a/integration_tests/recipes/f2py-example/source/pyproject.toml
+++ b/integration_tests/recipes/numpy-scripts-example/source/pyproject.toml
@@ -3,7 +3,7 @@ build-backend = "mesonpy"
 requires = ["meson-python", "numpy"]
 
 [project]
-name = "f2py-example"
+name = "numpy-scripts-example"
 version = "0.1.0"
 requires-python = ">=3.9"
 dependencies = ["numpy"]

From a9d4841e518874d4445dec090d8eebe321600e7b Mon Sep 17 00:00:00 2001
From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com>
Date: Sat, 27 Jun 2026 06:20:59 +0530
Subject: [PATCH 58/71] Repack dummy xbuildenv without `unisolated.txt`

---
 .../_test_xbuildenv/xbuildenv-test.tar.gz     | Bin 88189 -> 92674 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)

diff --git a/pyodide_build/tests/_test_xbuildenv/xbuildenv-test.tar.gz b/pyodide_build/tests/_test_xbuildenv/xbuildenv-test.tar.gz
index a20ea97a9fdf14348cf61f514db0e3ec16fa3175..c290981223e3f2621a60661c42755045d85d13d0 100644
GIT binary patch
literal 92674
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 GBnJSJHPx2@ literal 88189 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ౚ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 From a89865784681ee85d22ed941ee8ea00cb5e34b5f Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 27 Jun 2026 06:42:40 +0530 Subject: [PATCH 59/71] Update test to handle unisolated package version mismatch warning --- pyodide_build/tests/test_pypabuild.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pyodide_build/tests/test_pypabuild.py b/pyodide_build/tests/test_pypabuild.py index c321fb1a..820df85d 100644 --- a/pyodide_build/tests/test_pypabuild.py +++ b/pyodide_build/tests/test_pypabuild.py @@ -60,17 +60,15 @@ def test_replace_unisolated_packages_normalizes_names(): def test_replace_unisolated_packages_version_mismatch(): - """ - FIXME: This is not an ideal behavior, but for now we just ignore the version mismatch. - """ requires = {"baz==1.0"} unisolated = { "baz": "1.1", } - new_requires, replaced = pypabuild._replace_unisolated_packages( - requires, unisolated - ) + with pytest.warns(UserWarning, match=r"cross-build version is baz==1\.1"): + new_requires, replaced = pypabuild._replace_unisolated_packages( + requires, unisolated + ) assert new_requires == {"baz==1.1"} assert replaced == {"baz"} From 53e5f9180621575744a8fad8d6ae02390cd37205 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 27 Jun 2026 06:43:23 +0530 Subject: [PATCH 60/71] Add line in between --- pyodide_build/pypabuild.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index 7e3e5484..66337f9a 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -226,6 +226,7 @@ def install_reqs( os.environ | {k: v for k, v in build_env.items() if k.startswith("PIP")} ): env.install(reqs) + _install_cross_build_files(env.path, unisolated) From 38edec2f5374d840a206ab305d64ca74fca388f9 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 27 Jun 2026 19:04:34 +0530 Subject: [PATCH 61/71] Explicitly reject `oldest-supported-numpy` Co-Authored-By: Hood Chatham --- CHANGELOG.md | 7 +++---- pyodide_build/pypabuild.py | 6 ++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f47bb15d..7d3ad793 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -85,10 +85,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `numpy-config` from NumPy) not being available on `PATH` during builds. [#21](https://github.com/pyodide/pyodide-build/pull/21) -- `oldest-supported-numpy` is no longer silently ignored when encountered as a - build-time dependency. It will now be installed like any other package. Since - `oldest-supported-numpy` is deprecated since NumPy 2.0, packages that still - list it should migrate to a direct `numpy` dependency. +- `oldest-supported-numpy` is now explicitly rejected when encountered as a + build-time dependency. It is deprecated since NumPy 2.0, and packages that + still list it should migrate to a direct `numpy` dependency. [#21](https://github.com/pyodide/pyodide-build/pull/21) ## [0.34.4] - 2026/05/15 diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index 79cfe63e..054efdf7 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -142,6 +142,12 @@ def _replace_unisolated_packages( unisolated: set[str] = set() for reqstr in reqs: req = Requirement(reqstr) + if canonicalize_name(req.name) == "oldest-supported-numpy": + raise ValueError( + f"Build dependency '{reqstr}' is not supported. " + "oldest-supported-numpy is deprecated since NumPy 2.0. " + "Use a direct 'numpy' dependency instead." + ) match = canonical_unisolated.get(canonicalize_name(req.name)) if match is None: continue From 2c055139d76af149ea4d8b07de13c8547db96cf0 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 27 Jun 2026 19:07:28 +0530 Subject: [PATCH 62/71] Raise `FileNotFoundError` for non-existent xbuildenv requirements file Co-Authored-By: Hood Chatham --- pyodide_build/build_env.py | 26 +++++++++++++++----------- pyodide_build/tests/test_build_env.py | 3 ++- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/pyodide_build/build_env.py b/pyodide_build/build_env.py index dedb1041..2f4afc2b 100644 --- a/pyodide_build/build_env.py +++ b/pyodide_build/build_env.py @@ -241,17 +241,21 @@ def get_unisolated_packages() -> dict[str, str]: if in_xbuildenv(): unisolated_packages_file = PYODIDE_ROOT / ".." / "requirements.txt" - if unisolated_packages_file.exists(): - for line in unisolated_packages_file.read_text().splitlines(): - line = line.strip() - # The xbuildenv requirements.txt is machine-generated and always - # uses pinned name==version entries, but we skip blank lines, - # comments, and any non-pinned specs just in case. Shouldn't - # really happen though. - if not line or line.startswith("#") or "==" not in line: - continue - name, version = line.split("==", 1) - unisolated_packages[name] = version + if not unisolated_packages_file.exists(): + raise FileNotFoundError( + f"Expected {unisolated_packages_file} to exist in the xbuildenv. " + "The xbuildenv archive may be corrupt or from an incompatible version." + ) + for line in unisolated_packages_file.read_text().splitlines(): + line = line.strip() + # The xbuildenv requirements.txt is machine-generated and always + # uses pinned name==version entries, but we skip blank lines, + # comments, and any non-pinned specs just in case. Shouldn't + # really happen though. + if not line or line.startswith("#") or "==" not in line: + continue + name, version = line.split("==", 1) + unisolated_packages[name] = version else: from pyodide_build.recipe.loader import load_all_recipes diff --git a/pyodide_build/tests/test_build_env.py b/pyodide_build/tests/test_build_env.py index 8204a8da..c0d27253 100644 --- a/pyodide_build/tests/test_build_env.py +++ b/pyodide_build/tests/test_build_env.py @@ -80,7 +80,8 @@ def test_get_unisolated_packages_no_requirements_file( requirements_file = manager.pyodide_root / ".." / "requirements.txt" requirements_file.unlink() - assert build_env.get_unisolated_packages() == {} + with pytest.raises(FileNotFoundError, match="Expected .* to exist"): + build_env.get_unisolated_packages() def test_get_cross_build_files_dir( self, dummy_xbuildenv, reset_env_vars, reset_cache From 8e682f998211f708d91f80c6b0755cf668ebdf50 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 27 Jun 2026 19:16:30 +0530 Subject: [PATCH 63/71] Add comment about skipping cross-build file installation --- pyodide_build/pypabuild.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index 054efdf7..0a358aae 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -186,6 +186,9 @@ def _install_cross_build_files(venv_path: str, unisolated: set[str]) -> None: for name in unisolated: package_dir = get_cross_build_files_dir(name) if not package_dir.is_dir(): + # Not every unisolated package has cross-build files. The package + # may only need to be pinned to the cross-build version (for its + # console scripts, for instance) without any file overlay. continue shutil.copytree(package_dir, sitepackagesdir / name, dirs_exist_ok=True) From a8f63ffb40030fb658c848d2dea8b71c7dd0d937 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 27 Jun 2026 19:21:00 +0530 Subject: [PATCH 64/71] Shapely was using oldest-supported-numpy, bump its version --- integration_tests/recipes/shapely/meta.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration_tests/recipes/shapely/meta.yaml b/integration_tests/recipes/shapely/meta.yaml index 30eaca00..e24b5e82 100644 --- a/integration_tests/recipes/shapely/meta.yaml +++ b/integration_tests/recipes/shapely/meta.yaml @@ -1,11 +1,11 @@ package: name: shapely - version: 2.0.7 + version: 2.1.2 top-level: - shapely source: - url: https://files.pythonhosted.org/packages/21/c0/a911d1fd765d07a2b6769ce155219a281bfbe311584ebe97340d75c5bdb1/shapely-2.0.7.tar.gz - sha256: 28fe2997aab9a9dc026dc6a355d04e85841546b2a5d232ed953e3321ab958ee5 + url: https://files.pythonhosted.org/packages/source/s/shapely/shapely-2.1.2.tar.gz + sha256: 2ed4ecb28320a433db18a5bf029986aa8afcfd740745e78847e330d5d94922a9 build: vendor-sharedlib: true script: | From a5bbea20537997a294b93da8cd9942641b617c56 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 27 Jun 2026 19:24:40 +0530 Subject: [PATCH 65/71] Revert "Shapely was using oldest-supported-numpy, bump its version" This reverts commit a8f63ffb40030fb658c848d2dea8b71c7dd0d937. --- integration_tests/recipes/shapely/meta.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/integration_tests/recipes/shapely/meta.yaml b/integration_tests/recipes/shapely/meta.yaml index e24b5e82..30eaca00 100644 --- a/integration_tests/recipes/shapely/meta.yaml +++ b/integration_tests/recipes/shapely/meta.yaml @@ -1,11 +1,11 @@ package: name: shapely - version: 2.1.2 + version: 2.0.7 top-level: - shapely source: - url: https://files.pythonhosted.org/packages/source/s/shapely/shapely-2.1.2.tar.gz - sha256: 2ed4ecb28320a433db18a5bf029986aa8afcfd740745e78847e330d5d94922a9 + url: https://files.pythonhosted.org/packages/21/c0/a911d1fd765d07a2b6769ce155219a281bfbe311584ebe97340d75c5bdb1/shapely-2.0.7.tar.gz + sha256: 28fe2997aab9a9dc026dc6a355d04e85841546b2a5d232ed953e3321ab958ee5 build: vendor-sharedlib: true script: | From ea0f5140e0aae3db87128b08b33aebd371c47c70 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 27 Jun 2026 19:25:50 +0530 Subject: [PATCH 66/71] Evaluate PEP 508 markers for build-time reqs We were incorrectly pulling in the oldest-supported-numpy dependency at build time despite it being marked for usage by Shapely only for Python 3.9. --- pyodide_build/pypabuild.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index 0a358aae..953c7541 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -142,6 +142,8 @@ def _replace_unisolated_packages( unisolated: set[str] = set() for reqstr in reqs: req = Requirement(reqstr) + if req.marker and not req.marker.evaluate(): + continue if canonicalize_name(req.name) == "oldest-supported-numpy": raise ValueError( f"Build dependency '{reqstr}' is not supported. " From 78cc998d0ef545ab4106f7a5f78524fe5fdea678 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sat, 27 Jun 2026 19:30:35 +0530 Subject: [PATCH 67/71] Same bug for removing avoided requirements --- pyodide_build/pypabuild.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index 953c7541..73163484 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -214,6 +214,8 @@ def remove_avoided_requirements( """ for reqstr in list(requires): req = Requirement(reqstr) + if req.marker and not req.marker.evaluate(): + continue for avoid_name in set(avoided_requirements): if avoid_name == req.name.lower(): requires.remove(reqstr) From 86104b951da82b0d7b2c00c96a3b09c0cbdd45e4 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sun, 28 Jun 2026 01:26:02 +0530 Subject: [PATCH 68/71] Fix order in CHANGELOG + adjust version --- CHANGELOG.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d3ad793..e0c8cc6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.36.0] - 2026/MM/DD ### Fixed @@ -50,6 +50,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 setting `UV_BUILD_CONSTRAINT` alongside `PIP_CONSTRAINT` and `PIP_BUILD_CONSTRAINT`. [#389](https://github.com/pyodide/pyodide-build/pull/389) +### Changed + +- Fixed build-time scripts of unisolated packages (like `f2py` and + `numpy-config` from NumPy) not being available on `PATH` during builds. + [#21](https://github.com/pyodide/pyodide-build/pull/21) + +- `oldest-supported-numpy` is now explicitly rejected when encountered as a + build-time dependency. It is deprecated since NumPy 2.0, and packages that + still list it should migrate to a direct `numpy` dependency. + [#21](https://github.com/pyodide/pyodide-build/pull/21) + ## [0.35.1] - 2026/06/13 ### Fixed @@ -79,17 +90,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 additionally receive a `-v` flag for detailed package resolution output. [#363](https://github.com/pyodide/pyodide-build/pull/363) -### Changed - -- Fixed build-time scripts of unisolated packages (like `f2py` and - `numpy-config` from NumPy) not being available on `PATH` during builds. - [#21](https://github.com/pyodide/pyodide-build/pull/21) - -- `oldest-supported-numpy` is now explicitly rejected when encountered as a - build-time dependency. It is deprecated since NumPy 2.0, and packages that - still list it should migrate to a direct `numpy` dependency. - [#21](https://github.com/pyodide/pyodide-build/pull/21) - ## [0.34.4] - 2026/05/15 ### Added From cb3f8a8342a8e7462a0ed0e1b0e2a604a21afecf Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Sun, 28 Jun 2026 02:56:43 +0530 Subject: [PATCH 69/71] Add `numpy.pc` through `PKG_CONFIG_LIBDIR` --- pyodide_build/pypabuild.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index 73163484..883a81cb 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -243,6 +243,19 @@ def install_reqs( _install_cross_build_files(env.path, unisolated) +# So far among all packages in pyodide-recipes, only NumPy ships +# a .pc file, but I don't want to hardcode that here as such +def _get_unisolated_pkgconfig_dirs(venv_path: str) -> list[str]: + """ + Find directories containing .pc files shipped by packages installed in the + isolated build environment. These need to be added to PKG_CONFIG_LIBDIR so + that meson can discover unisolated packages (like numpy) via pkg-config + during cross-compilation. + """ + _, _, purelib = _find_executable_and_scripts(venv_path) + return list({str(pc.parent) for pc in Path(purelib).rglob("*.pc") if pc.is_file()}) + + def _build_in_isolated_env( build_env: Mapping[str, str], srcdir: Path, @@ -292,6 +305,14 @@ def _build_in_isolated_env( install_reqs(build_env, env, build_reqs) + pkgconfig_dirs = _get_unisolated_pkgconfig_dirs(env.path) + if pkgconfig_dirs: + build_env = dict(build_env) + existing = build_env.get("PKG_CONFIG_LIBDIR", "") + build_env["PKG_CONFIG_LIBDIR"] = ":".join( + [existing, *pkgconfig_dirs] if existing else pkgconfig_dirs + ) + with common.replace_env(build_env): return builder.build( distribution, From c90969e949b43acbaf53a366f7d5ae52ce33d092 Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Tue, 30 Jun 2026 19:50:02 +0530 Subject: [PATCH 70/71] Revert oldest-supported-numpy change for now --- CHANGELOG.md | 5 ----- pyodide_build/constants.py | 1 + pyodide_build/pypabuild.py | 6 ------ 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0c8cc6a..cf220bde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,11 +56,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 `numpy-config` from NumPy) not being available on `PATH` during builds. [#21](https://github.com/pyodide/pyodide-build/pull/21) -- `oldest-supported-numpy` is now explicitly rejected when encountered as a - build-time dependency. It is deprecated since NumPy 2.0, and packages that - still list it should migrate to a direct `numpy` dependency. - [#21](https://github.com/pyodide/pyodide-build/pull/21) - ## [0.35.1] - 2026/06/13 ### Fixed diff --git a/pyodide_build/constants.py b/pyodide_build/constants.py index 9f8903a5..53d275d3 100644 --- a/pyodide_build/constants.py +++ b/pyodide_build/constants.py @@ -4,4 +4,5 @@ BASE_IGNORED_REQUIREMENTS: list[str] = [ # mesonpy installs patchelf in linux platform but we don't want it. "patchelf", + "oldest-supported-numpy", ] diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index 883a81cb..06ba6ba1 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -144,12 +144,6 @@ def _replace_unisolated_packages( req = Requirement(reqstr) if req.marker and not req.marker.evaluate(): continue - if canonicalize_name(req.name) == "oldest-supported-numpy": - raise ValueError( - f"Build dependency '{reqstr}' is not supported. " - "oldest-supported-numpy is deprecated since NumPy 2.0. " - "Use a direct 'numpy' dependency instead." - ) match = canonical_unisolated.get(canonicalize_name(req.name)) if match is None: continue From 304bab0f18b12b2ea3b496b05f2ba6129c34d8ae Mon Sep 17 00:00:00 2001 From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> Date: Tue, 30 Jun 2026 19:51:05 +0530 Subject: [PATCH 71/71] Add comment about PEP 508 and `evaluate()` --- pyodide_build/pypabuild.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyodide_build/pypabuild.py b/pyodide_build/pypabuild.py index 06ba6ba1..8eb6807e 100644 --- a/pyodide_build/pypabuild.py +++ b/pyodide_build/pypabuild.py @@ -142,6 +142,8 @@ def _replace_unisolated_packages( unisolated: set[str] = set() for reqstr in reqs: req = Requirement(reqstr) + # Evaluate the PEP 508 marker to see if the requirement + # is applicable in the current environment or not. if req.marker and not req.marker.evaluate(): continue match = canonical_unisolated.get(canonicalize_name(req.name)) @@ -208,6 +210,8 @@ def remove_avoided_requirements( """ for reqstr in list(requires): req = Requirement(reqstr) + # Evaluate the PEP 508 marker to see if the requirement + # is applicable in the current environment or not. if req.marker and not req.marker.evaluate(): continue for avoid_name in set(avoided_requirements):