From 2c07c849b57463debbca505a439ab3b2aa2744a9 Mon Sep 17 00:00:00 2001 From: Francesco Christopher Date: Thu, 8 Jan 2026 18:40:28 +0100 Subject: [PATCH 1/8] test patches --- .gitignore | 25 + nerfstudio.code-workspace | 84 +++ nerfstudio/configs/360.gin | 15 + nerfstudio/configs/360_glo.gin | 15 + nerfstudio/configs/blender.gin | 15 + nerfstudio/configs/blender_refnerf.gin | 41 + nerfstudio/configs/llff_256.gin | 19 + nerfstudio/configs/llff_512.gin | 19 + nerfstudio/configs/llff_raw.gin | 73 ++ nerfstudio/configs/multi360.gin | 5 + .../process_data/colmap_utils - Copia.py | 714 ++++++++++++++++++ nerfstudio/scripts/exporter_frank.py | 676 +++++++++++++++++ ...tudio_stable_environment_post_zipnerf.yaml | 319 ++++++++ requirements_post_zipnerf - Copia.txt | 253 +++++++ requirements_post_zipnerf.txt | 251 ++++++ 15 files changed, 2524 insertions(+) create mode 100644 nerfstudio.code-workspace create mode 100644 nerfstudio/configs/360.gin create mode 100644 nerfstudio/configs/360_glo.gin create mode 100644 nerfstudio/configs/blender.gin create mode 100644 nerfstudio/configs/blender_refnerf.gin create mode 100644 nerfstudio/configs/llff_256.gin create mode 100644 nerfstudio/configs/llff_512.gin create mode 100644 nerfstudio/configs/llff_raw.gin create mode 100644 nerfstudio/configs/multi360.gin create mode 100644 nerfstudio/process_data/colmap_utils - Copia.py create mode 100644 nerfstudio/scripts/exporter_frank.py create mode 100644 nerfstudio_stable_environment_post_zipnerf.yaml create mode 100644 requirements_post_zipnerf - Copia.txt create mode 100644 requirements_post_zipnerf.txt diff --git a/.gitignore b/.gitignore index 28afce358a..f2f95b5401 100644 --- a/.gitignore +++ b/.gitignore @@ -188,6 +188,31 @@ camera_paths/ */**/.DS_Store */**/._.DS_Store +#Requirements and test stuff: +# Root-level exclusions +/*.txt +/*.pdf +/*.yml +/*.yaml + +# ✅ Exceptions: Include specific files in root dir +!requirements_post_zipnerf.txt +!requirements_post_zipnerf - Copia.txt +!nerfstudio_stable_environment_post_zipnerf.yaml +# External Submodules: +NeRFtoGSandBack/ +glomap/ +instruct-gs2gs/ +opennerf/ +pytorch_scatter/ +splatfacto-w/ +src/igs2gs/ +src/nerfgs/ +src/splatfacto-w/ +src/zipnerf/ +tetra-nerf/ +zipnerf-pytorch/ + # pixi environments .pixi /third_party \ No newline at end of file diff --git a/nerfstudio.code-workspace b/nerfstudio.code-workspace new file mode 100644 index 0000000000..5e645c9817 --- /dev/null +++ b/nerfstudio.code-workspace @@ -0,0 +1,84 @@ +{ + "folders": [ + { + "path": "." + }, + { + "path": "../nerfstudio1.0.3" + }, + { + "path": "../neuralangelo" + }, + { + "path": "../sdfstudio" + } + ], + "settings": { + "javascript.validate.enable": false, + "files.associations": { + "array": "cpp", + "bitset": "cpp", + "string_view": "cpp", + "initializer_list": "cpp", + "utility": "cpp", + "__hash_table": "cpp", + "__split_buffer": "cpp", + "deque": "cpp", + "iterator": "cpp", + "queue": "cpp", + "stack": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "atomic": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "codecvt": "cpp", + "condition_variable": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "filesystem": "cpp", + "functional": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "optional": "cpp", + "ratio": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "fstream": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "mutex": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "typeinfo": "cpp", + "__nullptr": "cpp", + "__config": "cpp", + "__locale": "cpp", + "__bit_reference": "cpp", + "ios": "cpp", + "__atomic": "cpp", + "__node_handle": "cpp" + } + } +} \ No newline at end of file diff --git a/nerfstudio/configs/360.gin b/nerfstudio/configs/360.gin new file mode 100644 index 0000000000..d39fe8bab2 --- /dev/null +++ b/nerfstudio/configs/360.gin @@ -0,0 +1,15 @@ +Config.exp_name = 'test' +Config.dataset_loader = 'llff' +Config.near = 0.2 +Config.far = 1e6 +Config.factor = 4 + +Model.raydist_fn = 'power_transformation' +Model.opaque_background = True + +PropMLP.disable_density_normals = True +PropMLP.disable_rgb = True +PropMLP.grid_level_dim = 1 + +NerfMLP.disable_density_normals = True + diff --git a/nerfstudio/configs/360_glo.gin b/nerfstudio/configs/360_glo.gin new file mode 100644 index 0000000000..42a2436218 --- /dev/null +++ b/nerfstudio/configs/360_glo.gin @@ -0,0 +1,15 @@ +Config.dataset_loader = 'llff' +Config.near = 0.2 +Config.far = 1e6 +Config.factor = 4 + +Model.raydist_fn = 'power_transformation' +Model.num_glo_features = 128 +Model.opaque_background = True + +PropMLP.disable_density_normals = True +PropMLP.disable_rgb = True +PropMLP.grid_level_dim = 1 + + +NerfMLP.disable_density_normals = True diff --git a/nerfstudio/configs/blender.gin b/nerfstudio/configs/blender.gin new file mode 100644 index 0000000000..20f74c9d27 --- /dev/null +++ b/nerfstudio/configs/blender.gin @@ -0,0 +1,15 @@ +Config.exp_name = 'test' +Config.dataset_loader = 'blender' +Config.near = 2 +Config.far = 6 +Config.factor = 0 +Config.hash_decay_mults = 10 + +Model.raydist_fn = None + +PropMLP.disable_density_normals = True +PropMLP.disable_rgb = True +PropMLP.grid_level_dim = 1 + +NerfMLP.disable_density_normals = True + diff --git a/nerfstudio/configs/blender_refnerf.gin b/nerfstudio/configs/blender_refnerf.gin new file mode 100644 index 0000000000..42da4df7dc --- /dev/null +++ b/nerfstudio/configs/blender_refnerf.gin @@ -0,0 +1,41 @@ +Config.dataset_loader = 'blender' +Config.batching = 'single_image' +Config.near = 2 +Config.far = 6 + +Config.eval_render_interval = 5 +Config.compute_normal_metrics = True +Config.data_loss_type = 'mse' +Config.distortion_loss_mult = 0.0 +Config.orientation_loss_mult = 0.1 +Config.orientation_loss_target = 'normals_pred' +Config.predicted_normal_loss_mult = 3e-4 +Config.orientation_coarse_loss_mult = 0.01 +Config.predicted_normal_coarse_loss_mult = 3e-5 +Config.interlevel_loss_mult = 0.0 +Config.data_coarse_loss_mult = 0.1 +Config.adam_eps = 1e-8 + +Model.num_levels = 2 +Model.single_mlp = True +Model.num_prop_samples = 128 # This needs to be set despite single_mlp = True. +Model.num_nerf_samples = 128 +Model.anneal_slope = 0. +Model.dilation_multiplier = 0. +Model.dilation_bias = 0. +Model.single_jitter = False +Model.resample_padding = 0.01 +Model.distinct_prop = False + +NerfMLP.disable_density_normals = False +NerfMLP.enable_pred_normals = True +NerfMLP.use_directional_enc = True +NerfMLP.use_reflections = True +NerfMLP.deg_view = 5 +NerfMLP.enable_pred_roughness = True +NerfMLP.use_diffuse_color = True +NerfMLP.use_specular_tint = True +NerfMLP.use_n_dot_v = True +NerfMLP.bottleneck_width = 128 +NerfMLP.density_bias = 0.5 +NerfMLP.max_deg_point = 16 diff --git a/nerfstudio/configs/llff_256.gin b/nerfstudio/configs/llff_256.gin new file mode 100644 index 0000000000..eeeba4fc80 --- /dev/null +++ b/nerfstudio/configs/llff_256.gin @@ -0,0 +1,19 @@ +Config.dataset_loader = 'llff' +Config.near = 0. +Config.far = 1. +Config.factor = 4 +Config.forward_facing = True +Config.adam_eps = 1e-8 + +Model.opaque_background = True +Model.num_levels = 2 +Model.num_prop_samples = 128 +Model.num_nerf_samples = 32 + +PropMLP.disable_density_normals = True +PropMLP.disable_rgb = True + +NerfMLP.disable_density_normals = True + +NerfMLP.max_deg_point = 16 +PropMLP.max_deg_point = 16 diff --git a/nerfstudio/configs/llff_512.gin b/nerfstudio/configs/llff_512.gin new file mode 100644 index 0000000000..eeeba4fc80 --- /dev/null +++ b/nerfstudio/configs/llff_512.gin @@ -0,0 +1,19 @@ +Config.dataset_loader = 'llff' +Config.near = 0. +Config.far = 1. +Config.factor = 4 +Config.forward_facing = True +Config.adam_eps = 1e-8 + +Model.opaque_background = True +Model.num_levels = 2 +Model.num_prop_samples = 128 +Model.num_nerf_samples = 32 + +PropMLP.disable_density_normals = True +PropMLP.disable_rgb = True + +NerfMLP.disable_density_normals = True + +NerfMLP.max_deg_point = 16 +PropMLP.max_deg_point = 16 diff --git a/nerfstudio/configs/llff_raw.gin b/nerfstudio/configs/llff_raw.gin new file mode 100644 index 0000000000..343f226b90 --- /dev/null +++ b/nerfstudio/configs/llff_raw.gin @@ -0,0 +1,73 @@ +# General LLFF settings + +Config.dataset_loader = 'llff' +Config.near = 0. +Config.far = 1. +Config.factor = 4 +Config.forward_facing = True + +PropMLP.disable_density_normals = True # Turn this off if using orientation loss. +PropMLP.disable_rgb = True + +NerfMLP.disable_density_normals = True # Turn this off if using orientation loss. + +NerfMLP.max_deg_point = 16 +PropMLP.max_deg_point = 16 + +Config.train_render_every = 5000 + + +########################## RawNeRF specific settings ########################## + +Config.rawnerf_mode = True +Config.data_loss_type = 'rawnerf' +Config.apply_bayer_mask = True +Model.learned_exposure_scaling = True + +Model.num_levels = 2 +Model.num_prop_samples = 128 # Using extra samples for now because of noise instability. +Model.num_nerf_samples = 128 +Model.opaque_background = True +Model.distinct_prop = False + +# RGB activation we use for linear color outputs is exp(x - 5). +NerfMLP.rgb_padding = 0. +NerfMLP.rgb_activation = @math.safe_exp +NerfMLP.rgb_bias = -5. +PropMLP.rgb_padding = 0. +PropMLP.rgb_activation = @math.safe_exp +PropMLP.rgb_bias = -5. + +## Experimenting with the various regularizers and losses: +Config.interlevel_loss_mult = .0 # Turning off interlevel for now (default = 1.). +Config.distortion_loss_mult = .01 # Distortion loss helps with floaters (default = .01). +Config.orientation_loss_mult = 0. # Orientation loss also not great (try .01). +Config.data_coarse_loss_mult = 0.1 # Setting this to match old MipNeRF. + +## Density noise used in original NeRF: +NerfMLP.density_noise = 1. +PropMLP.density_noise = 1. + +## Use a single MLP for all rounds of sampling: +Model.single_mlp = True + +## Some algorithmic settings to match the paper: +Model.anneal_slope = 0. +Model.dilation_multiplier = 0. +Model.dilation_bias = 0. +Model.single_jitter = False +NerfMLP.weight_init = 'glorot_uniform' +PropMLP.weight_init = 'glorot_uniform' + +## Training hyperparameters used in the paper: +Config.batch_size = 16384 +Config.render_chunk_size = 16384 +Config.lr_init = 1e-3 +Config.lr_final = 1e-5 +Config.max_steps = 500000 +Config.checkpoint_every = 25000 +Config.lr_delay_steps = 2500 +Config.lr_delay_mult = 0.01 +Config.grad_max_norm = 0.1 +Config.grad_max_val = 0.1 +Config.adam_eps = 1e-8 diff --git a/nerfstudio/configs/multi360.gin b/nerfstudio/configs/multi360.gin new file mode 100644 index 0000000000..e9bef1a30c --- /dev/null +++ b/nerfstudio/configs/multi360.gin @@ -0,0 +1,5 @@ +include 'configs/360.gin' +Config.multiscale = True +Config.multiscale_levels = 4 + + diff --git a/nerfstudio/process_data/colmap_utils - Copia.py b/nerfstudio/process_data/colmap_utils - Copia.py new file mode 100644 index 0000000000..1d9405c81a --- /dev/null +++ b/nerfstudio/process_data/colmap_utils - Copia.py @@ -0,0 +1,714 @@ +# Copyright 2022 the Regents of the University of California, Nerfstudio Team and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Tools supporting the execution of COLMAP and preparation of COLMAP-based datasets for nerfstudio training. +""" + +import json +from pathlib import Path +from typing import Any, Dict, Literal, Optional, Union + +import appdirs +import cv2 +import numpy as np +import requests +import torch +from packaging.version import Version +from rich.progress import track + +# TODO(1480) use pycolmap instead of colmap_parsing_utils +# import pycolmap +from nerfstudio.data.utils.colmap_parsing_utils import ( + qvec2rotmat, + read_cameras_binary, + read_images_binary, + read_points3D_binary, + read_points3D_text, +) +from nerfstudio.process_data.process_data_utils import CameraModel +from nerfstudio.utils import colormaps +from nerfstudio.utils.rich_utils import CONSOLE, status +from nerfstudio.utils.scripts import run_command + + +def get_colmap_version(colmap_cmd: str, default_version: str = "3.8") -> Version: + """Returns the version of COLMAP. + This code assumes that colmap returns a version string of the form + "COLMAP 3.8 ..." which may not be true for all versions of COLMAP. + + Args: + default_version: Default version to return if COLMAP version can't be determined. + Returns: + The version of COLMAP. + """ + output = run_command(f"{colmap_cmd} -h", verbose=False) + assert output is not None + for line in output.split("\n"): + if line.startswith("COLMAP"): + version = line.split(" ")[1] + version = Version(version) + return version + CONSOLE.print(f"[bold red]Could not find COLMAP version. Using default {default_version}") + return Version(default_version) + + +def get_vocab_tree() -> Path: + """Return path to vocab tree. Downloads vocab tree if it doesn't exist. + + Returns: + The path to the vocab tree. + """ + vocab_tree_filename = Path(appdirs.user_data_dir("nerfstudio")) / "vocab_tree.fbow" + + if not vocab_tree_filename.exists(): + r = requests.get("https://demuc.de/colmap/vocab_tree_flickr100K_words32K.bin", stream=True) + vocab_tree_filename.parent.mkdir(parents=True, exist_ok=True) + with open(vocab_tree_filename, "wb") as f: + total_length = r.headers.get("content-length") + assert total_length is not None + for chunk in track( + r.iter_content(chunk_size=1024), + total=int(total_length) / 1024 + 1, + description="Downloading vocab tree...", + ): + if chunk: + f.write(chunk) + f.flush() + return vocab_tree_filename + + +def run_colmap( + image_dir: Path, + colmap_dir: Path, + camera_model: CameraModel, + camera_mask_path: Optional[Path] = None, + gpu: bool = True, + verbose: bool = False, + matching_method: Literal["vocab_tree", "exhaustive", "sequential"] = "vocab_tree", + refine_intrinsics: bool = True, + colmap_cmd: str = "colmap", +) -> None: + """Runs COLMAP on the images. + + Args: + image_dir: Path to the directory containing the images. + colmap_dir: Path to the output directory. + camera_model: Camera model to use. + camera_mask_path: Path to the camera mask. + gpu: If True, use GPU. + verbose: If True, logs the output of the command. + matching_method: Matching method to use. + refine_intrinsics: If True, refine intrinsics. + colmap_cmd: Path to the COLMAP executable. + """ + + colmap_version = get_colmap_version(colmap_cmd) + + colmap_database_path = colmap_dir / "database.db" + colmap_database_path.unlink(missing_ok=True) + + # Feature extraction + feature_extractor_cmd = [ + f"{colmap_cmd} feature_extractor", + f"--database_path {colmap_dir / 'database.db'}", + f"--image_path {image_dir}", + "--ImageReader.single_camera 1", + f"--ImageReader.camera_model {camera_model.value}", + f"--SiftExtraction.use_gpu {int(gpu)}", + ] + if camera_mask_path is not None: + feature_extractor_cmd.append(f"--ImageReader.camera_mask_path {camera_mask_path}") + feature_extractor_cmd = " ".join(feature_extractor_cmd) + with status(msg="[bold yellow]Running COLMAP feature extractor...", spinner="moon", verbose=verbose): + run_command(feature_extractor_cmd, verbose=verbose) + + CONSOLE.log("[bold green]:tada: Done extracting COLMAP features.") + + # Feature matching + feature_matcher_cmd = [ + f"{colmap_cmd} {matching_method}_matcher", + f"--database_path {colmap_dir / 'database.db'}", + f"--SiftMatching.use_gpu {int(gpu)}", + ] + if matching_method == "vocab_tree": + vocab_tree_filename = get_vocab_tree() + feature_matcher_cmd.append(f'--VocabTreeMatching.vocab_tree_path "{vocab_tree_filename}"') + feature_matcher_cmd = " ".join(feature_matcher_cmd) + with status(msg="[bold yellow]Running COLMAP feature matcher...", spinner="runner", verbose=verbose): + run_command(feature_matcher_cmd, verbose=verbose) + CONSOLE.log("[bold green]:tada: Done matching COLMAP features.") + + # Bundle adjustment + sparse_dir = colmap_dir / "sparse" + sparse_dir.mkdir(parents=True, exist_ok=True) + mapper_cmd = [ + f"{colmap_cmd} mapper", + f"--database_path {colmap_dir / 'database.db'}", + f"--image_path {image_dir}", + f"--output_path {sparse_dir}", + ] + if colmap_version >= Version("3.7"): + mapper_cmd.append("--Mapper.ba_global_function_tolerance=1e-6") + + mapper_cmd = " ".join(mapper_cmd) + + with status( + msg="[bold yellow]Running COLMAP bundle adjustment... (This may take a while)", + spinner="circle", + verbose=verbose, + ): + run_command(mapper_cmd, verbose=verbose) + CONSOLE.log("[bold green]:tada: Done COLMAP bundle adjustment.") + + if refine_intrinsics: + with status(msg="[bold yellow]Refine intrinsics...", spinner="dqpb", verbose=verbose): + bundle_adjuster_cmd = [ + f"{colmap_cmd} bundle_adjuster", + f"--input_path {sparse_dir}/0", + f"--output_path {sparse_dir}/0", + "--BundleAdjustment.refine_principal_point 1", + ] + run_command(" ".join(bundle_adjuster_cmd), verbose=verbose) + CONSOLE.log("[bold green]:tada: Done refining intrinsics.") + + +def parse_colmap_camera_params(camera) -> Dict[str, Any]: + """ + Parses all currently supported COLMAP cameras into the transforms.json metadata + + Args: + camera: COLMAP camera + Returns: + transforms.json metadata containing camera's intrinsics and distortion parameters + + """ + out: Dict[str, Any] = { + "w": camera.width, + "h": camera.height, + } + + # Parameters match https://github.com/colmap/colmap/blob/dev/src/base/camera_models.h + camera_params = camera.params + if camera.model == "SIMPLE_PINHOLE": + # du = 0 + # dv = 0 + out["fl_x"] = float(camera_params[0]) + out["fl_y"] = float(camera_params[0]) + out["cx"] = float(camera_params[1]) + out["cy"] = float(camera_params[2]) + out["k1"] = 0.0 + out["k2"] = 0.0 + out["p1"] = 0.0 + out["p2"] = 0.0 + camera_model = CameraModel.OPENCV + elif camera.model == "PINHOLE": + # f, cx, cy, k + + # du = 0 + # dv = 0 + out["fl_x"] = float(camera_params[0]) + out["fl_y"] = float(camera_params[1]) + out["cx"] = float(camera_params[2]) + out["cy"] = float(camera_params[3]) + out["k1"] = 0.0 + out["k2"] = 0.0 + out["p1"] = 0.0 + out["p2"] = 0.0 + camera_model = CameraModel.OPENCV + elif camera.model == "SIMPLE_RADIAL": + # f, cx, cy, k + + # r2 = u**2 + v**2; + # radial = k * r2 + # du = u * radial + # dv = u * radial + out["fl_x"] = float(camera_params[0]) + out["fl_y"] = float(camera_params[0]) + out["cx"] = float(camera_params[1]) + out["cy"] = float(camera_params[2]) + out["k1"] = float(camera_params[3]) + out["k2"] = 0.0 + out["p1"] = 0.0 + out["p2"] = 0.0 + camera_model = CameraModel.OPENCV + elif camera.model == "RADIAL": + # f, cx, cy, k1, k2 + + # r2 = u**2 + v**2; + # radial = k1 * r2 + k2 * r2 ** 2 + # du = u * radial + # dv = v * radial + out["fl_x"] = float(camera_params[0]) + out["fl_y"] = float(camera_params[0]) + out["cx"] = float(camera_params[1]) + out["cy"] = float(camera_params[2]) + out["k1"] = float(camera_params[3]) + out["k2"] = float(camera_params[4]) + out["p1"] = 0.0 + out["p2"] = 0.0 + camera_model = CameraModel.OPENCV + elif camera.model == "OPENCV": + # fx, fy, cx, cy, k1, k2, p1, p2 + + # uv = u * v; + # r2 = u**2 + v**2 + # radial = k1 * r2 + k2 * r2 ** 2 + # du = u * radial + 2 * p1 * u*v + p2 * (r2 + 2 * u**2) + # dv = v * radial + 2 * p2 * u*v + p1 * (r2 + 2 * v**2) + out["fl_x"] = float(camera_params[0]) + out["fl_y"] = float(camera_params[1]) + out["cx"] = float(camera_params[2]) + out["cy"] = float(camera_params[3]) + out["k1"] = float(camera_params[4]) + out["k2"] = float(camera_params[5]) + out["p1"] = float(camera_params[6]) + out["p2"] = float(camera_params[7]) + camera_model = CameraModel.OPENCV + elif camera.model == "OPENCV_FISHEYE": + # fx, fy, cx, cy, k1, k2, k3, k4 + + # r = sqrt(u**2 + v**2) + + # if r > eps: + # theta = atan(r) + # theta2 = theta ** 2 + # theta4 = theta2 ** 2 + # theta6 = theta4 * theta2 + # theta8 = theta4 ** 2 + # thetad = theta * (1 + k1 * theta2 + k2 * theta4 + k3 * theta6 + k4 * theta8) + # du = u * thetad / r - u; + # dv = v * thetad / r - v; + # else: + # du = dv = 0 + out["fl_x"] = float(camera_params[0]) + out["fl_y"] = float(camera_params[1]) + out["cx"] = float(camera_params[2]) + out["cy"] = float(camera_params[3]) + out["k1"] = float(camera_params[4]) + out["k2"] = float(camera_params[5]) + out["k3"] = float(camera_params[6]) + out["k4"] = float(camera_params[7]) + camera_model = CameraModel.OPENCV_FISHEYE + elif camera.model == "FULL_OPENCV": + # fx, fy, cx, cy, k1, k2, p1, p2, k3, k4, k5, k6 + + # u2 = u ** 2 + # uv = u * v + # v2 = v ** 2 + # r2 = u2 + v2 + # r4 = r2 * r2 + # r6 = r4 * r2 + # radial = (1 + k1 * r2 + k2 * r4 + k3 * r6) / + # (1 + k4 * r2 + k5 * r4 + k6 * r6) + # du = u * radial + 2 * p1 * uv + p2 * (r2 + 2 * u2) - u + # dv = v * radial + 2 * p2 * uv + p1 * (r2 + 2 * v2) - v + out["fl_x"] = float(camera_params[0]) + out["fl_y"] = float(camera_params[1]) + out["cx"] = float(camera_params[2]) + out["cy"] = float(camera_params[3]) + out["k1"] = float(camera_params[4]) + out["k2"] = float(camera_params[5]) + out["p1"] = float(camera_params[6]) + out["p2"] = float(camera_params[7]) + out["k3"] = float(camera_params[8]) + out["k4"] = float(camera_params[9]) + out["k5"] = float(camera_params[10]) + out["k6"] = float(camera_params[11]) + raise NotImplementedError(f"{camera.model} camera model is not supported yet!") + elif camera.model == "FOV": + # fx, fy, cx, cy, omega + out["fl_x"] = float(camera_params[0]) + out["fl_y"] = float(camera_params[1]) + out["cx"] = float(camera_params[2]) + out["cy"] = float(camera_params[3]) + out["omega"] = float(camera_params[4]) + raise NotImplementedError(f"{camera.model} camera model is not supported yet!") + elif camera.model == "SIMPLE_RADIAL_FISHEYE": + # f, cx, cy, k + + # r = sqrt(u ** 2 + v ** 2) + # if r > eps: + # theta = atan(r) + # theta2 = theta ** 2 + # thetad = theta * (1 + k * theta2) + # du = u * thetad / r - u; + # dv = v * thetad / r - v; + # else: + # du = dv = 0 + out["fl_x"] = float(camera_params[0]) + out["fl_y"] = float(camera_params[0]) + out["cx"] = float(camera_params[1]) + out["cy"] = float(camera_params[2]) + out["k1"] = float(camera_params[3]) + out["k2"] = 0.0 + out["k3"] = 0.0 + out["k4"] = 0.0 + camera_model = CameraModel.OPENCV_FISHEYE + elif camera.model == "RADIAL_FISHEYE": + # f, cx, cy, k1, k2 + + # r = sqrt(u ** 2 + v ** 2) + # if r > eps: + # theta = atan(r) + # theta2 = theta ** 2 + # theta4 = theta2 ** 2 + # thetad = theta * (1 + k * theta2) + # thetad = theta * (1 + k1 * theta2 + k2 * theta4) + # du = u * thetad / r - u; + # dv = v * thetad / r - v; + # else: + # du = dv = 0 + out["fl_x"] = float(camera_params[0]) + out["fl_y"] = float(camera_params[0]) + out["cx"] = float(camera_params[1]) + out["cy"] = float(camera_params[2]) + out["k1"] = float(camera_params[3]) + out["k2"] = float(camera_params[4]) + out["k3"] = 0 + out["k4"] = 0 + camera_model = CameraModel.OPENCV_FISHEYE + else: + # THIN_PRISM_FISHEYE not supported! + raise NotImplementedError(f"{camera.model} camera model is not supported yet!") + + out["camera_model"] = camera_model.value + return out + + +def colmap_to_json( + recon_dir: Path, + output_dir: Path, + camera_mask_path: Optional[Path] = None, + image_id_to_depth_path: Optional[Dict[int, Path]] = None, + image_rename_map: Optional[Dict[str, str]] = None, + ply_filename="sparse_pc.ply", + keep_original_world_coordinate: bool = False, + use_single_camera_mode: bool = True, +) -> int: + """Converts COLMAP's cameras.bin and images.bin to a JSON file. + + Args: + recon_dir: Path to the reconstruction directory, e.g. "sparse/0" + output_dir: Path to the output directory. + camera_model: Camera model used. + camera_mask_path: Path to the camera mask. + image_id_to_depth_path: When including sfm-based depth, embed these depth file paths in the exported json + image_rename_map: Use these image names instead of the names embedded in the COLMAP db + keep_original_world_coordinate: If True, no extra transform will be applied to world coordinate. + Colmap optimized world often have y direction of the first camera pointing towards down direction, + while nerfstudio world set z direction to be up direction for viewer. + Returns: + The number of registered images. + """ + + # TODO(1480) use pycolmap + # recon = pycolmap.Reconstruction(recon_dir) + # cam_id_to_camera = recon.cameras + # im_id_to_image = recon.images + cam_id_to_camera = read_cameras_binary(recon_dir / "cameras.bin") + im_id_to_image = read_images_binary(recon_dir / "images.bin") + if set(cam_id_to_camera.keys()) != {1}: + CONSOLE.print(f"[bold yellow]Warning: More than one camera is found in {recon_dir}") + print(cam_id_to_camera) + use_single_camera_mode = False # update bool: one camera per frame + out = {} # out = {"camera_model": parse_colmap_camera_params(cam_id_to_camera[1])["camera_model"]} + else: # one camera for all frames + out = parse_colmap_camera_params(cam_id_to_camera[1]) + + frames = [] + for im_id, im_data in im_id_to_image.items(): + # NB: COLMAP uses Eigen / scalar-first quaternions + # * https://colmap.github.io/format.html + # * https://github.com/colmap/colmap/blob/bf3e19140f491c3042bfd85b7192ef7d249808ec/src/base/pose.cc#L75 + # the `rotation_matrix()` handles that format for us. + + # TODO(1480) BEGIN use pycolmap API + # rotation = im_data.rotation_matrix() + rotation = qvec2rotmat(im_data.qvec) + + translation = im_data.tvec.reshape(3, 1) + w2c = np.concatenate([rotation, translation], 1) + w2c = np.concatenate([w2c, np.array([[0, 0, 0, 1]])], 0) + c2w = np.linalg.inv(w2c) + # Convert from COLMAP's camera coordinate system (OpenCV) to ours (OpenGL) + c2w[0:3, 1:3] *= -1 + if not keep_original_world_coordinate: + c2w = c2w[np.array([0, 2, 1, 3]), :] + c2w[2, :] *= -1 + + name = im_data.name + if image_rename_map is not None: + name = image_rename_map[name] + name = Path(f"./images/{name}") + + frame = { + "file_path": name.as_posix(), + "transform_matrix": c2w.tolist(), + "colmap_im_id": im_id, + } + if camera_mask_path is not None: + frame["mask_path"] = camera_mask_path.relative_to(camera_mask_path.parent.parent).as_posix() + if image_id_to_depth_path is not None: + depth_path = image_id_to_depth_path[im_id] + frame["depth_file_path"] = str(depth_path.relative_to(depth_path.parent.parent)) + + if not use_single_camera_mode: # add the camera parameters for this frame + frame.update(parse_colmap_camera_params(cam_id_to_camera[im_data.camera_id])) + + frames.append(frame) + + out["frames"] = frames + + applied_transform = None + if not keep_original_world_coordinate: + applied_transform = np.eye(4)[:3, :] + applied_transform = applied_transform[np.array([0, 2, 1]), :] + applied_transform[2, :] *= -1 + out["applied_transform"] = applied_transform.tolist() + + # create ply from colmap + assert ply_filename.endswith(".ply"), f"ply_filename: {ply_filename} does not end with '.ply'" + create_ply_from_colmap( + ply_filename, + recon_dir, + output_dir, + torch.from_numpy(applied_transform).float() if applied_transform is not None else None, + ) + out["ply_file_path"] = ply_filename + + with open(output_dir / "transforms.json", "w", encoding="utf-8") as f: + json.dump(out, f, indent=4) + + return len(frames) + + +def create_sfm_depth( + recon_dir: Path, + output_dir: Path, + verbose: bool = True, + depth_scale_to_integer_factor: float = 1000.0, + min_depth: float = 0.001, + max_depth: float = 10000, + max_repoj_err: float = 2.5, + min_n_visible: int = 2, + include_depth_debug: bool = False, + input_images_dir: Optional[Path] = None, +) -> Dict[int, Path]: + """Converts COLMAP's points3d.bin to sparse depth map images encoded as + 16-bit "millimeter depth" PNGs. + + Notes: + * This facility does NOT use COLMAP dense reconstruction; it creates depth + maps from sparse SfM points here. + * COLMAP does *not* reconstruct metric depth unless you give it calibrated + (metric) intrinsics as input. Therefore, "depth" in this function has + potentially ambiguous units. + + Args: + recon_dir: Path to the reconstruction directory, e.g. "sparse/0" + output_dir: Path to the output directory. + verbose: If True, logs progress of depth image creation. + depth_scale_to_integer_factor: Use this parameter to tune the conversion of + raw depth measurements to integer depth values. This value should + be equal to 1. / `depth_unit_scale_factor`, where + `depth_unit_scale_factor` is the value you provide at training time. + E.g. for millimeter depth, leave `depth_unit_scale_factor` at 1e-3 + and depth_scale_to_integer_factor at 1000. + min_depth: Discard points closer than this to the camera. + max_depth: Discard points farther than this from the camera. + max_repoj_err: Discard points with reprojection error greater than this + amount (in pixels). + min_n_visible: Discard 3D points that have been triangulated with fewer + than this many frames. + include_depth_debug: Also include debug images showing depth overlaid + upon RGB. + Returns: + Depth file paths indexed by COLMAP image id + """ + + # TODO(1480) use pycolmap + # recon = pycolmap.Reconstruction(recon_dir) + # ptid_to_info = recon.points3D + # cam_id_to_camera = recon.cameras + # im_id_to_image = recon.images + ptid_to_info = read_points3D_binary(recon_dir / "points3D.bin") + cam_id_to_camera = read_cameras_binary(recon_dir / "cameras.bin") + im_id_to_image = read_images_binary(recon_dir / "images.bin") + + # Only support first camera + CAMERA_ID = 1 + W = cam_id_to_camera[CAMERA_ID].width + H = cam_id_to_camera[CAMERA_ID].height + + if verbose: + iter_images = track( + im_id_to_image.items(), total=len(im_id_to_image.items()), description="Creating depth maps ..." + ) + else: + iter_images = iter(im_id_to_image.items()) + + image_id_to_depth_path = {} + for im_id, im_data in iter_images: + # TODO(1480) BEGIN delete when abandoning colmap_parsing_utils + pids = [pid for pid in im_data.point3D_ids if pid != -1] + xyz_world = np.array([ptid_to_info[pid].xyz for pid in pids]) + rotation = qvec2rotmat(im_data.qvec) + z = (rotation @ xyz_world.T)[-1] + im_data.tvec[-1] + errors = np.array([ptid_to_info[pid].error for pid in pids]) + n_visible = np.array([len(ptid_to_info[pid].image_ids) for pid in pids]) + uv = np.array([im_data.xys[i] for i in range(len(im_data.xys)) if im_data.point3D_ids[i] != -1]) + # TODO(1480) END delete when abandoning colmap_parsing_utils + + # TODO(1480) BEGIN use pycolmap API + + # # Get only keypoints that have corresponding triangulated 3D points + # p2ds = im_data.get_valid_points2D() + + # xyz_world = np.array([ptid_to_info[p2d.point3D_id].xyz for p2d in p2ds]) + + # # COLMAP OpenCV convention: z is always positive + # z = (im_data.rotation_matrix() @ xyz_world.T)[-1] + im_data.tvec[-1] + + # # Mean reprojection error in image space + # errors = np.array([ptid_to_info[p2d.point3D_id].error for p2d in p2ds]) + + # # Number of frames in which each frame is visible + # n_visible = np.array([ptid_to_info[p2d.point3D_id].track.length() for p2d in p2ds]) + + # Note: these are *unrectified* pixel coordinates that should match the original input + # no matter the camera model + # uv = np.array([p2d.xy for p2d in p2ds]) + + # TODO(1480) END use pycolmap API + + idx = np.where( + (z >= min_depth) + & (z <= max_depth) + & (errors <= max_repoj_err) + & (n_visible >= min_n_visible) + & (uv[:, 0] >= 0) + & (uv[:, 0] < W) + & (uv[:, 1] >= 0) + & (uv[:, 1] < H) + ) + z = z[idx] + uv = uv[idx] + + uu, vv = uv[:, 0].astype(int), uv[:, 1].astype(int) + depth = np.zeros((H, W), dtype=np.float32) + depth[vv, uu] = z + + # E.g. if `depth` is metric and in units of meters, and `depth_scale_to_integer_factor` + # is 1000, then `depth_img` will be integer millimeters. + depth_img = (depth_scale_to_integer_factor * depth).astype(np.uint16) + + out_name = str(im_data.name) + depth_path = output_dir / out_name + if depth_path.suffix == ".jpg": + depth_path = depth_path.with_suffix(".png") + cv2.imwrite(str(depth_path), depth_img) # type: ignore + + image_id_to_depth_path[im_id] = depth_path + + if include_depth_debug: + assert input_images_dir is not None, "Need explicit input_images_dir for debug images" + assert input_images_dir.exists(), input_images_dir + + depth_flat = depth.flatten()[:, None] + overlay = 255.0 * colormaps.apply_depth_colormap(torch.from_numpy(depth_flat)).numpy() + overlay = overlay.reshape([H, W, 3]) + input_image_path = input_images_dir / im_data.name + input_image = cv2.imread(str(input_image_path)) # type: ignore + debug = 0.3 * input_image + 0.7 + overlay + + out_name = out_name + ".debug.jpg" + output_path = output_dir / "debug_depth" / out_name + output_path.parent.mkdir(parents=True, exist_ok=True) + cv2.imwrite(str(output_path), debug.astype(np.uint8)) # type: ignore + + return image_id_to_depth_path + + +def get_matching_summary(num_initial_frames: int, num_matched_frames: int) -> str: + """Returns a summary of the matching results. + + Args: + num_initial_frames: The number of initial frames. + num_matched_frames: The number of matched frames. + + Returns: + A summary of the matching results. + """ + match_ratio = num_matched_frames / num_initial_frames + if match_ratio == 1: + return "[bold green]COLMAP found poses for all images, CONGRATS!" + if match_ratio < 0.4: + result = f"[bold red]COLMAP only found poses for {num_matched_frames / num_initial_frames * 100:.2f}%" + result += " of the images. This is low.\nThis can be caused by a variety of reasons," + result += " such poor scene coverage, blurry images, or large exposure changes." + return result + if match_ratio < 0.8: + result = f"[bold yellow]COLMAP only found poses for {num_matched_frames / num_initial_frames * 100:.2f}%" + result += " of the images.\nThis isn't great, but may be ok." + result += "\nMissing poses can be caused by a variety of reasons, such poor scene coverage, blurry images," + result += " or large exposure changes." + return result + return f"[bold green]COLMAP found poses for {num_matched_frames / num_initial_frames * 100:.2f}% of the images." + + +def create_ply_from_colmap( + filename: str, recon_dir: Path, output_dir: Path, applied_transform: Union[torch.Tensor, None] +) -> None: + """Writes a ply file from colmap. + + Args: + filename: file name for .ply + recon_dir: Directory to grab colmap points + output_dir: Directory to output .ply + """ + if (recon_dir / "points3D.bin").exists(): + colmap_points = read_points3D_binary(recon_dir / "points3D.bin") + elif (recon_dir / "points3D.txt").exists(): + colmap_points = read_points3D_text(recon_dir / "points3D.txt") + else: + raise ValueError(f"Could not find points3D.txt or points3D.bin in {recon_dir}") + + # Load point Positions + points3D = torch.from_numpy(np.array([p.xyz for p in colmap_points.values()], dtype=np.float32)) + if applied_transform is not None: + assert applied_transform.shape == (3, 4) + points3D = torch.einsum("ij,bj->bi", applied_transform[:3, :3], points3D) + applied_transform[:3, 3] + + # Load point colours + points3D_rgb = torch.from_numpy(np.array([p.rgb for p in colmap_points.values()], dtype=np.uint8)) + + # write ply + with open(output_dir / filename, "w") as f: + # Header + f.write("ply\n") + f.write("format ascii 1.0\n") + f.write(f"element vertex {len(points3D)}\n") + f.write("property float x\n") + f.write("property float y\n") + f.write("property float z\n") + f.write("property uint8 red\n") + f.write("property uint8 green\n") + f.write("property uint8 blue\n") + f.write("end_header\n") + + for coord, color in zip(points3D, points3D_rgb): + x, y, z = coord + r, g, b = color + f.write(f"{x:8f} {y:8f} {z:8f} {r} {g} {b}\n") diff --git a/nerfstudio/scripts/exporter_frank.py b/nerfstudio/scripts/exporter_frank.py new file mode 100644 index 0000000000..7d7d54be40 --- /dev/null +++ b/nerfstudio/scripts/exporter_frank.py @@ -0,0 +1,676 @@ +# Copyright 2022 the Regents of the University of California, Nerfstudio Team and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Script for exporting NeRF into other formats. +""" + +from __future__ import annotations + +import json +import os +import sys +import typing +from collections import OrderedDict +from dataclasses import dataclass, field +from importlib.metadata import version +from pathlib import Path +from typing import List, Optional, Tuple, Union, cast + +import numpy as np +import open3d as o3d +import torch +import tyro +from typing_extensions import Annotated, Literal + +from nerfstudio.cameras.rays import RayBundle +from nerfstudio.data.datamanagers.full_images_datamanager import FullImageDatamanager +from nerfstudio.data.datamanagers.random_cameras_datamanager import RandomCamerasDataManager +from nerfstudio.data.datamanagers.base_datamanager import VanillaDataManager +from nerfstudio.data.datamanagers.parallel_datamanager import ParallelDataManager +from nerfstudio.data.scene_box import OrientedBox +from nerfstudio.exporter import texture_utils, tsdf_utils +from nerfstudio.exporter.exporter_utils import collect_camera_poses, generate_point_cloud, get_mesh_from_filename +from nerfstudio.exporter.marching_cubes import generate_mesh_with_multires_marching_cubes +from nerfstudio.fields.sdf_field import SDFField # noqa +from nerfstudio.models.splatfacto import SplatfactoModel +from nerfstudio.pipelines.base_pipeline import Pipeline, VanillaPipeline +from nerfstudio.utils.eval_utils import eval_setup +from nerfstudio.utils.rich_utils import CONSOLE + + +@dataclass +class Exporter: + """Export the mesh from a YML config to a folder.""" + + load_config: Path + """Path to the config YAML file.""" + output_dir: Path + """Path to the output directory.""" + + +def validate_pipeline(normal_method: str, normal_output_name: str, pipeline: Pipeline) -> None: + """Check that the pipeline is valid for this exporter. + + Args: + normal_method: Method to estimate normals with. Either "open3d" or "model_output". + normal_output_name: Name of the normal output. + pipeline: Pipeline to evaluate with. + """ + if normal_method == "model_output": + CONSOLE.print("Checking that the pipeline has a normal output.") + origins = torch.zeros((1, 3), device=pipeline.device) + directions = torch.ones_like(origins) + pixel_area = torch.ones_like(origins[..., :1]) + camera_indices = torch.zeros_like(origins[..., :1]) + metadata = {"directions_norm": torch.linalg.vector_norm(directions, dim=-1, keepdim=True)} + ray_bundle = RayBundle( + origins=origins, + directions=directions, + pixel_area=pixel_area, + camera_indices=camera_indices, + metadata=metadata, + ) + outputs = pipeline.model(ray_bundle) + if normal_output_name not in outputs: + CONSOLE.print(f"[bold yellow]Warning: Normal output '{normal_output_name}' not found in pipeline outputs.") + CONSOLE.print(f"Available outputs: {list(outputs.keys())}") + CONSOLE.print( + "[bold yellow]Warning: Please train a model with normals " + "(e.g., nerfacto with predicted normals turned on)." + ) + CONSOLE.print("[bold yellow]Warning: Or change --normal-method") + CONSOLE.print("[bold yellow]Exiting early.") + sys.exit(1) + + +@dataclass +class ExportPointCloud(Exporter): + """Export NeRF as a point cloud.""" + + num_points: int = 1000000 + """Number of points to generate. May result in less if outlier removal is used.""" + remove_outliers: bool = True + """Remove outliers from the point cloud.""" + reorient_normals: bool = True + """Reorient point cloud normals based on view direction.""" + normal_method: Literal["open3d", "model_output"] = "model_output" + """Method to estimate normals with.""" + normal_output_name: str = "normals" + """Name of the normal output.""" + depth_output_name: str = "depth" + """Name of the depth output.""" + rgb_output_name: str = "rgb" + """Name of the RGB output.""" + + obb_center: Optional[Tuple[float, float, float]] = None + """Center of the oriented bounding box.""" + obb_rotation: Optional[Tuple[float, float, float]] = None + """Rotation of the oriented bounding box. Expressed as RPY Euler angles in radians""" + obb_scale: Optional[Tuple[float, float, float]] = None + """Scale of the oriented bounding box along each axis.""" + num_rays_per_batch: int = 32768 + """Number of rays to evaluate per batch. Decrease if you run out of memory.""" + std_ratio: float = 10.0 + """Threshold based on STD of the average distances across the point cloud to remove outliers.""" + save_world_frame: bool = False + """If set, saves the point cloud in the same frame as the original dataset. Otherwise, uses the + scaled and reoriented coordinate space expected by the NeRF models.""" + + def main(self) -> None: + """Export point cloud.""" + + if not self.output_dir.exists(): + self.output_dir.mkdir(parents=True) + + _, pipeline, _, _ = eval_setup(self.load_config) + + validate_pipeline(self.normal_method, self.normal_output_name, pipeline) + + # Increase the batchsize to speed up the evaluation. + assert isinstance( + pipeline.datamanager, + (VanillaDataManager, ParallelDataManager,FullImageDatamanager, RandomCamerasDataManager)) + if isinstance(pipeline.datamanager, VanillaDataManager): + assert pipeline.datamanager.train_pixel_sampler is not None + pipeline.datamanager.train_pixel_sampler.num_rays_per_batch = self.num_rays_per_batch + + # Whether the normals should be estimated based on the point cloud. + estimate_normals = self.normal_method == "open3d" + crop_obb = None + if self.obb_center is not None and self.obb_rotation is not None and self.obb_scale is not None: + crop_obb = OrientedBox.from_params(self.obb_center, self.obb_rotation, self.obb_scale) + pcd = generate_point_cloud( + pipeline=pipeline, + num_points=self.num_points, + remove_outliers=self.remove_outliers, + reorient_normals=self.reorient_normals, + estimate_normals=estimate_normals, + rgb_output_name=self.rgb_output_name, + depth_output_name=self.depth_output_name, + normal_output_name=self.normal_output_name if self.normal_method == "model_output" else None, + crop_obb=crop_obb, + std_ratio=self.std_ratio, + ) + if self.save_world_frame: + # apply the inverse dataparser transform to the point cloud + points = np.asarray(pcd.points) + poses = np.eye(4, dtype=np.float32)[None, ...].repeat(points.shape[0], axis=0)[:, :3, :] + poses[:, :3, 3] = points + poses = pipeline.datamanager.train_dataparser_outputs.transform_poses_to_original_space( + torch.from_numpy(poses) + ) + points = poses[:, :3, 3].numpy() + pcd.points = o3d.utility.Vector3dVector(points) + + torch.cuda.empty_cache() + + CONSOLE.print(f"[bold green]:white_check_mark: Generated {pcd}") + CONSOLE.print("Saving Point Cloud...") + tpcd = o3d.t.geometry.PointCloud.from_legacy(pcd) + # The legacy PLY writer converts colors to UInt8, + # let us do the same to save space. + tpcd.point.colors = (tpcd.point.colors * 255).to(o3d.core.Dtype.UInt8) # type: ignore + o3d.t.io.write_point_cloud(str(self.output_dir / "point_cloud.ply"), tpcd) + print("\033[A\033[A") + CONSOLE.print("[bold green]:white_check_mark: Saving Point Cloud") + + +@dataclass +class ExportTSDFMesh(Exporter): + """ + Export a mesh using TSDF processing. + """ + + downscale_factor: int = 2 + """Downscale the images starting from the resolution used for training.""" + depth_output_name: str = "depth" + """Name of the depth output.""" + rgb_output_name: str = "rgb" + """Name of the RGB output.""" + resolution: Union[int, List[int]] = field(default_factory=lambda: [128, 128, 128]) + """Resolution of the TSDF volume or [x, y, z] resolutions individually.""" + batch_size: int = 10 + """How many depth images to integrate per batch.""" + use_bounding_box: bool = True + """Whether to use a bounding box for the TSDF volume.""" + bounding_box_min: Tuple[float, float, float] = (-1, -1, -1) + """Minimum of the bounding box, used if use_bounding_box is True.""" + bounding_box_max: Tuple[float, float, float] = (1, 1, 1) + """Minimum of the bounding box, used if use_bounding_box is True.""" + texture_method: Literal["tsdf", "nerf"] = "nerf" + """Method to texture the mesh with. Either 'tsdf' or 'nerf'.""" + px_per_uv_triangle: int = 4 + """Number of pixels per UV triangle.""" + unwrap_method: Literal["xatlas", "custom"] = "xatlas" + """The method to use for unwrapping the mesh.""" + num_pixels_per_side: int = 2048 + """If using xatlas for unwrapping, the pixels per side of the texture image.""" + target_num_faces: Optional[int] = 50000 + """Target number of faces for the mesh to texture.""" + refine_mesh_using_initial_aabb_estimate: bool = False + """Refine the mesh using the initial AABB estimate.""" + refinement_epsilon: float = 1e-2 + """Refinement epsilon for the mesh. This is the distance in meters that the refined AABB/OBB will be expanded by + in each direction.""" + + def main(self) -> None: + """Export mesh""" + + if not self.output_dir.exists(): + self.output_dir.mkdir(parents=True) + + _, pipeline, _, _ = eval_setup(self.load_config) + + tsdf_utils.export_tsdf_mesh( + pipeline, + self.output_dir, + self.downscale_factor, + self.depth_output_name, + self.rgb_output_name, + self.resolution, + self.batch_size, + use_bounding_box=self.use_bounding_box, + bounding_box_min=self.bounding_box_min, + bounding_box_max=self.bounding_box_max, + refine_mesh_using_initial_aabb_estimate=self.refine_mesh_using_initial_aabb_estimate, + refinement_epsilon=self.refinement_epsilon, + ) + + # possibly + # texture the mesh with NeRF and export to a mesh.obj file + # and a material and texture file + if self.texture_method == "nerf": + # load the mesh from the tsdf export + mesh = get_mesh_from_filename( + str(self.output_dir / "tsdf_mesh.ply"), target_num_faces=self.target_num_faces + ) + CONSOLE.print("Texturing mesh with NeRF") + texture_utils.export_textured_mesh( + mesh, + pipeline, + self.output_dir, + px_per_uv_triangle=self.px_per_uv_triangle if self.unwrap_method == "custom" else None, + unwrap_method=self.unwrap_method, + num_pixels_per_side=self.num_pixels_per_side, + ) + + +@dataclass +class ExportPoissonMesh(Exporter): + """ + Export a mesh using poisson surface reconstruction. + """ + + num_points: int = 1000000 + """Number of points to generate. May result in less if outlier removal is used.""" + remove_outliers: bool = True + """Remove outliers from the point cloud.""" + reorient_normals: bool = True + """Reorient point cloud normals based on view direction.""" + depth_output_name: str = "depth" + """Name of the depth output.""" + rgb_output_name: str = "rgb" + """Name of the RGB output.""" + normal_method: Literal["open3d", "model_output"] = "model_output" + """Method to estimate normals with.""" + normal_output_name: str = "normals" + """Name of the normal output.""" + save_point_cloud: bool = False + """Whether to save the point cloud.""" + obb_center: Optional[Tuple[float, float, float]] = None + """Center of the oriented bounding box.""" + obb_rotation: Optional[Tuple[float, float, float]] = None + """Rotation of the oriented bounding box. Expressed as RPY Euler angles in radians""" + obb_scale: Optional[Tuple[float, float, float]] = None + """Scale of the oriented bounding box along each axis.""" + num_rays_per_batch: int = 32768 + """Number of rays to evaluate per batch. Decrease if you run out of memory.""" + texture_method: Literal["point_cloud", "nerf"] = "nerf" + """Method to texture the mesh with. Either 'point_cloud' or 'nerf'.""" + px_per_uv_triangle: int = 4 + """Number of pixels per UV triangle.""" + unwrap_method: Literal["xatlas", "custom"] = "xatlas" + """The method to use for unwrapping the mesh.""" + num_pixels_per_side: int = 2048 + """If using xatlas for unwrapping, the pixels per side of the texture image.""" + target_num_faces: Optional[int] = 50000 + """Target number of faces for the mesh to texture.""" + std_ratio: float = 10.0 + """Threshold based on STD of the average distances across the point cloud to remove outliers.""" + + def main(self) -> None: + """Export mesh""" + + if not self.output_dir.exists(): + self.output_dir.mkdir(parents=True) + + _, pipeline, _, _ = eval_setup(self.load_config) + + validate_pipeline(self.normal_method, self.normal_output_name, pipeline) + + # Increase the batchsize to speed up the evaluation. + assert isinstance( + pipeline.datamanager, + (VanillaDataManager, ParallelDataManager,FullImageDatamanager,RandomCamerasDataManager)) + if isinstance(pipeline.datamanager, VanillaDataManager): + assert pipeline.datamanager.train_pixel_sampler is not None + pipeline.datamanager.train_pixel_sampler.num_rays_per_batch = self.num_rays_per_batch + + # Whether the normals should be estimated based on the point cloud. + estimate_normals = self.normal_method == "open3d" + if self.obb_center is not None and self.obb_rotation is not None and self.obb_scale is not None: + crop_obb = OrientedBox.from_params(self.obb_center, self.obb_rotation, self.obb_scale) + else: + crop_obb = None + + pcd = generate_point_cloud( + pipeline=pipeline, + num_points=self.num_points, + remove_outliers=self.remove_outliers, + reorient_normals=self.reorient_normals, + estimate_normals=estimate_normals, + rgb_output_name=self.rgb_output_name, + depth_output_name=self.depth_output_name, + normal_output_name=self.normal_output_name if self.normal_method == "model_output" else None, + crop_obb=crop_obb, + std_ratio=self.std_ratio, + ) + torch.cuda.empty_cache() + CONSOLE.print(f"[bold green]:white_check_mark: Generated {pcd}") + + if self.save_point_cloud: + CONSOLE.print("Saving Point Cloud...") + o3d.io.write_point_cloud(str(self.output_dir / "point_cloud.ply"), pcd) + print("\033[A\033[A") + CONSOLE.print("[bold green]:white_check_mark: Saving Point Cloud") + + CONSOLE.print("Computing Mesh... this may take a while.") + mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=9) + vertices_to_remove = densities < np.quantile(densities, 0.1) + mesh.remove_vertices_by_mask(vertices_to_remove) + print("\033[A\033[A") + CONSOLE.print("[bold green]:white_check_mark: Computing Mesh") + + CONSOLE.print("Saving Mesh...") + o3d.io.write_triangle_mesh(str(self.output_dir / "poisson_mesh.ply"), mesh) + print("\033[A\033[A") + CONSOLE.print("[bold green]:white_check_mark: Saving Mesh") + + # This will texture the mesh with NeRF and export to a mesh.obj file + # and a material and texture file + if self.texture_method == "nerf": + # load the mesh from the poisson reconstruction + mesh = get_mesh_from_filename( + str(self.output_dir / "poisson_mesh.ply"), target_num_faces=self.target_num_faces + ) + CONSOLE.print("Texturing mesh with NeRF") + texture_utils.export_textured_mesh( + mesh, + pipeline, + self.output_dir, + px_per_uv_triangle=self.px_per_uv_triangle if self.unwrap_method == "custom" else None, + unwrap_method=self.unwrap_method, + num_pixels_per_side=self.num_pixels_per_side, + ) + + +@dataclass +class ExportMarchingCubesMesh(Exporter): + """Export a mesh using marching cubes.""" + + isosurface_threshold: float = 0.0 + """The isosurface threshold for extraction. For SDF based methods the surface is the zero level set.""" + resolution: int = 1024 + """Marching cube resolution.""" + simplify_mesh: bool = False + """Whether to simplify the mesh.""" + bounding_box_min: Tuple[float, float, float] = (-1.0, -1.0, -1.0) + """Minimum of the bounding box.""" + bounding_box_max: Tuple[float, float, float] = (1.0, 1.0, 1.0) + """Maximum of the bounding box.""" + px_per_uv_triangle: int = 4 + """Number of pixels per UV triangle.""" + unwrap_method: Literal["xatlas", "custom"] = "xatlas" + """The method to use for unwrapping the mesh.""" + num_pixels_per_side: int = 2048 + """If using xatlas for unwrapping, the pixels per side of the texture image.""" + target_num_faces: Optional[int] = 50000 + """Target number of faces for the mesh to texture.""" + + def main(self) -> None: + """Main function.""" + if not self.output_dir.exists(): + self.output_dir.mkdir(parents=True) + + _, pipeline, _, _ = eval_setup(self.load_config) + + # TODO: Make this work with Density Field + assert hasattr(pipeline.model.config, "sdf_field"), "Model must have an SDF field." + + CONSOLE.print("Extracting mesh with marching cubes... which may take a while") + + assert self.resolution % 512 == 0, f"""resolution must be divisible by 512, got {self.resolution}. + This is important because the algorithm uses a multi-resolution approach + to evaluate the SDF where the minimum resolution is 512.""" + + # Extract mesh using marching cubes for sdf at a multi-scale resolution. + multi_res_mesh = generate_mesh_with_multires_marching_cubes( + geometry_callable_field=lambda x: cast(SDFField, pipeline.model.field) + .forward_geonetwork(x)[:, 0] + .contiguous(), + resolution=self.resolution, + bounding_box_min=self.bounding_box_min, + bounding_box_max=self.bounding_box_max, + isosurface_threshold=self.isosurface_threshold, + coarse_mask=None, + ) + filename = self.output_dir / "sdf_marching_cubes_mesh.ply" + multi_res_mesh.export(filename) + + # load the mesh from the marching cubes export + mesh = get_mesh_from_filename(str(filename), target_num_faces=self.target_num_faces) + CONSOLE.print("Texturing mesh with NeRF...") + texture_utils.export_textured_mesh( + mesh, + pipeline, + self.output_dir, + px_per_uv_triangle=self.px_per_uv_triangle if self.unwrap_method == "custom" else None, + unwrap_method=self.unwrap_method, + num_pixels_per_side=self.num_pixels_per_side, + ) + + +@dataclass +class ExportCameraPoses(Exporter): + """ + Export camera poses to a .json file. + """ + + def main(self) -> None: + """Export camera poses""" + if not self.output_dir.exists(): + self.output_dir.mkdir(parents=True) + + _, pipeline, _, _ = eval_setup(self.load_config) + assert isinstance(pipeline, VanillaPipeline) + train_frames, eval_frames = collect_camera_poses(pipeline) + + for file_name, frames in [("transforms_train.json", train_frames), ("transforms_eval.json", eval_frames)]: + if len(frames) == 0: + CONSOLE.print(f"[bold yellow]No frames found for {file_name}. Skipping.") + continue + + output_file_path = os.path.join(self.output_dir, file_name) + + with open(output_file_path, "w", encoding="UTF-8") as f: + json.dump(frames, f, indent=4) + + CONSOLE.print(f"[bold green]:white_check_mark: Saved poses to {output_file_path}") + + +@dataclass +class ExportGaussianSplat(Exporter): + """ + Export 3D Gaussian Splatting model to a .ply + """ + + output_filename: str = "splat.ply" + """Name of the output file.""" + obb_center: Optional[Tuple[float, float, float]] = None + """Center of the oriented bounding box.""" + obb_rotation: Optional[Tuple[float, float, float]] = None + """Rotation of the oriented bounding box. Expressed as RPY Euler angles in radians""" + obb_scale: Optional[Tuple[float, float, float]] = None + """Scale of the oriented bounding box along each axis.""" + ply_color_mode: Literal["sh_coeffs", "rgb"] = "sh_coeffs" + """If "rgb", export colors as red/green/blue fields. Otherwise, export colors as + spherical harmonics coefficients.""" + + @staticmethod + def write_ply( + filename: str, + count: int, + map_to_tensors: typing.OrderedDict[str, np.ndarray], + ): + """ + Writes a PLY file with given vertex properties and a tensor of float or uint8 values in the order specified by the OrderedDict. + Note: All float values will be converted to float32 for writing. + + Parameters: + filename (str): The name of the file to write. + count (int): The number of vertices to write. + map_to_tensors (OrderedDict[str, np.ndarray]): An ordered dictionary mapping property names to numpy arrays of float or uint8 values. + Each array should be 1-dimensional and of equal length matching 'count'. Arrays should not be empty. + """ + + # Ensure count matches the length of all tensors + if not all(tensor.size == count for tensor in map_to_tensors.values()): + raise ValueError("Count does not match the length of all tensors") + + # Type check for numpy arrays of type float or uint8 and non-empty + if not all( + isinstance(tensor, np.ndarray) + and (tensor.dtype.kind == "f" or tensor.dtype == np.uint8) + and tensor.size > 0 + for tensor in map_to_tensors.values() + ): + raise ValueError("All tensors must be numpy arrays of float or uint8 type and not empty") + + with open(filename, "wb") as ply_file: + nerfstudio_version = version("nerfstudio") + # Write PLY header + ply_file.write(b"ply\n") + ply_file.write(b"format binary_little_endian 1.0\n") + ply_file.write(f"comment Generated by Nerstudio {nerfstudio_version}\n".encode()) + ply_file.write(b"comment Vertical Axis: z\n") + ply_file.write(f"element vertex {count}\n".encode()) + + # Write properties, in order due to OrderedDict + for key, tensor in map_to_tensors.items(): + data_type = "float" if tensor.dtype.kind == "f" else "uchar" + ply_file.write(f"property {data_type} {key}\n".encode()) + + ply_file.write(b"end_header\n") + + # Write binary data + # Note: If this is a performance bottleneck consider using numpy.hstack for efficiency improvement + for i in range(count): + for tensor in map_to_tensors.values(): + value = tensor[i] + if tensor.dtype.kind == "f": + ply_file.write(np.float32(value).tobytes()) + elif tensor.dtype == np.uint8: + ply_file.write(value.tobytes()) + + def main(self) -> None: + if not self.output_dir.exists(): + self.output_dir.mkdir(parents=True) + + _, pipeline, _, _ = eval_setup(self.load_config, test_mode="inference") + + assert isinstance(pipeline.model, SplatfactoModel) + + model: SplatfactoModel = pipeline.model + + filename = self.output_dir / self.output_filename + + map_to_tensors = OrderedDict() + + with torch.no_grad(): + positions = model.means.cpu().numpy() + count = positions.shape[0] + n = count + map_to_tensors["x"] = positions[:, 0] + map_to_tensors["y"] = positions[:, 1] + map_to_tensors["z"] = positions[:, 2] + map_to_tensors["nx"] = np.zeros(n, dtype=np.float32) + map_to_tensors["ny"] = np.zeros(n, dtype=np.float32) + map_to_tensors["nz"] = np.zeros(n, dtype=np.float32) + + if self.ply_color_mode == "rgb": + colors = torch.clamp(model.colors.clone(), 0.0, 1.0).data.cpu().numpy() + colors = (colors * 255).astype(np.uint8) + map_to_tensors["red"] = colors[:, 0] + map_to_tensors["green"] = colors[:, 1] + map_to_tensors["blue"] = colors[:, 2] + elif self.ply_color_mode == "sh_coeffs": + shs_0 = model.shs_0.contiguous().cpu().numpy() + for i in range(shs_0.shape[1]): + map_to_tensors[f"f_dc_{i}"] = shs_0[:, i, None] + + if model.config.sh_degree > 0: + if self.ply_color_mode == "rgb": + CONSOLE.print( + "Warning: model has higher level of spherical harmonics, ignoring them and only export rgb." + ) + elif self.ply_color_mode == "sh_coeffs": + # transpose(1, 2) was needed to match the sh order in Inria version + shs_rest = model.shs_rest.transpose(1, 2).contiguous().cpu().numpy() + shs_rest = shs_rest.reshape((n, -1)) + for i in range(shs_rest.shape[-1]): + map_to_tensors[f"f_rest_{i}"] = shs_rest[:, i, None] + + map_to_tensors["opacity"] = model.opacities.data.cpu().numpy() + + scales = model.scales.data.cpu().numpy() + for i in range(3): + map_to_tensors[f"scale_{i}"] = scales[:, i, None] + + quats = model.quats.data.cpu().numpy() + for i in range(4): + map_to_tensors[f"rot_{i}"] = quats[:, i, None] + + if self.obb_center is not None and self.obb_rotation is not None and self.obb_scale is not None: + crop_obb = OrientedBox.from_params(self.obb_center, self.obb_rotation, self.obb_scale) + assert crop_obb is not None + mask = crop_obb.within(torch.from_numpy(positions)).numpy() + for k, t in map_to_tensors.items(): + map_to_tensors[k] = map_to_tensors[k][mask] + + n = map_to_tensors["x"].shape[0] + count = n + + # post optimization, it is possible have NaN/Inf values in some attributes + # to ensure the exported ply file has finite values, we enforce finite filters. + select = np.ones(n, dtype=bool) + for k, t in map_to_tensors.items(): + n_before = np.sum(select) + select = np.logical_and(select, np.isfinite(t).all(axis=-1)) + n_after = np.sum(select) + if n_after < n_before: + CONSOLE.print(f"{n_before - n_after} NaN/Inf elements in {k}") + nan_count = np.sum(select) - n + + # filter gaussians that have opacities < 1/255, because they are skipped in cuda rasterization + low_opacity_gaussians = (map_to_tensors["opacity"]).squeeze(axis=-1) < -5.5373 # logit(1/255) + lowopa_count = np.sum(low_opacity_gaussians) + select[low_opacity_gaussians] = 0 + + if np.sum(select) < n: + CONSOLE.print( + f"{nan_count} Gaussians have NaN/Inf and {lowopa_count} have low opacity, only export {np.sum(select)}/{n}" + ) + for k, t in map_to_tensors.items(): + map_to_tensors[k] = map_to_tensors[k][select] + count = np.sum(select) + + ExportGaussianSplat.write_ply(str(filename), count, map_to_tensors) + + +Commands = tyro.conf.FlagConversionOff[ + Union[ + Annotated[ExportPointCloud, tyro.conf.subcommand(name="pointcloud")], + Annotated[ExportTSDFMesh, tyro.conf.subcommand(name="tsdf")], + Annotated[ExportPoissonMesh, tyro.conf.subcommand(name="poisson")], + Annotated[ExportMarchingCubesMesh, tyro.conf.subcommand(name="marching-cubes")], + Annotated[ExportCameraPoses, tyro.conf.subcommand(name="cameras")], + Annotated[ExportGaussianSplat, tyro.conf.subcommand(name="gaussian-splat")], + ] +] + + +def entrypoint(): + """Entrypoint for use with pyproject scripts.""" + tyro.extras.set_accent_color("bright_yellow") + tyro.cli(Commands).main() + + +if __name__ == "__main__": + entrypoint() + + +def get_parser_fn(): + """Get the parser function for the sphinx docs.""" + return tyro.extras.get_parser(Commands) # noqa diff --git a/nerfstudio_stable_environment_post_zipnerf.yaml b/nerfstudio_stable_environment_post_zipnerf.yaml new file mode 100644 index 0000000000..91fb5ad9d7 --- /dev/null +++ b/nerfstudio_stable_environment_post_zipnerf.yaml @@ -0,0 +1,319 @@ +name: nerfstudio_test +channels: + - nvidia/label/cuda-11.8.0 + - defaults + - https://repo.anaconda.com/pkgs/main + - https://repo.anaconda.com/pkgs/r + - https://repo.anaconda.com/pkgs/msys2 +dependencies: + - bzip2=1.0.8=h2bbff1b_6 + - ca-certificates=2025.2.25=haa95532_0 + - cuda-cccl=11.8.89=0 + - cuda-command-line-tools=11.8.0=0 + - cuda-compiler=11.8.0=0 + - cuda-cudart=11.8.89=0 + - cuda-cudart-dev=11.8.89=0 + - cuda-cuobjdump=11.8.86=0 + - cuda-cupti=11.8.87=0 + - cuda-cuxxfilt=11.8.86=0 + - cuda-documentation=11.8.86=0 + - cuda-libraries=11.8.0=0 + - cuda-libraries-dev=11.8.0=0 + - cuda-memcheck=11.8.86=0 + - cuda-nsight-compute=11.8.0=0 + - cuda-nvcc=11.8.89=0 + - cuda-nvdisasm=11.8.86=0 + - cuda-nvml-dev=11.8.86=0 + - cuda-nvprof=11.8.87=0 + - cuda-nvprune=11.8.86=0 + - cuda-nvrtc=11.8.89=0 + - cuda-nvrtc-dev=11.8.89=0 + - cuda-nvtx=11.8.86=0 + - cuda-nvvp=11.8.87=0 + - cuda-profiler-api=11.8.86=0 + - cuda-sanitizer-api=11.8.86=0 + - cuda-toolkit=11.8.0=0 + - cuda-tools=11.8.0=0 + - cuda-visual-tools=11.8.0=0 + - libcublas=11.11.3.6=0 + - libcublas-dev=11.11.3.6=0 + - libcufft=10.9.0.58=0 + - libcufft-dev=10.9.0.58=0 + - libcurand=10.3.0.86=0 + - libcurand-dev=10.3.0.86=0 + - libcusolver=11.4.1.48=0 + - libcusolver-dev=11.4.1.48=0 + - libcusparse=11.7.5.86=0 + - libcusparse-dev=11.7.5.86=0 + - libffi=3.4.4=hd77b12b_1 + - libnpp=11.8.0.86=0 + - libnpp-dev=11.8.0.86=0 + - libnvjpeg=11.9.0.86=0 + - libnvjpeg-dev=11.9.0.86=0 + - nsight-compute=2022.3.0.22=0 + - openssl=3.0.16=h3f729d1_0 + - python=3.10.16=h4607a30_1 + - sqlite=3.45.3=h2bbff1b_0 + - tk=8.6.14=h0416ee5_0 + - vc=14.42=haa95532_4 + - vs2015_runtime=14.42.34433=he0abc0d_4 + - wheel=0.45.1=py310haa95532_0 + - xz=5.6.4=h4754444_1 + - zlib=1.2.13=h8cc25b3_1 + - pip: + - absl-py==2.2.2 + - accelerate==0.19.0 + - annotated-types==0.7.0 + - anyio==4.9.0 + - appdirs==1.4.4 + - argon2-cffi==23.1.0 + - argon2-cffi-bindings==21.2.0 + - arrow==1.3.0 + - asttokens==3.0.0 + - async-lru==2.0.5 + - attrs==25.3.0 + - av==14.3.0 + - babel==2.17.0 + - beautifulsoup4==4.13.3 + - bidict==0.23.1 + - bitsandbytes==0.43.0 + - bleach==6.2.0 + - blinker==1.9.0 + - cachetools==5.5.2 + - certifi==2025.1.31 + - cffi==1.17.1 + - charset-normalizer==3.4.1 + - click==8.1.8 + - colorama==0.4.6 + - colorlog==6.9.0 + - comet-ml==3.49.7 + - comm==0.2.2 + - configargparse==1.7 + - configobj==5.0.9 + - contourpy==1.3.1 + - cryptography==44.0.2 + - cuda-backend==0.0.0 + - cycler==0.12.1 + - dash==3.0.2 + - debugpy==1.8.14 + - decorator==5.2.1 + - defusedxml==0.7.1 + - descartes==1.1.0 + - diffusers==0.16.1 + - dill==0.3.9 + - docker-pycreds==0.4.0 + - docstring-parser==0.16 + - dulwich==0.22.8 + - everett==3.1.0 + - exceptiongroup==1.2.2 + - executing==2.2.0 + - fastjsonschema==2.21.1 + - filelock==3.18.0 + - fire==0.7.0 + - flask==3.0.3 + - fonttools==4.57.0 + - fpsample==0.3.3 + - fqdn==1.5.1 + - fsspec==2025.3.2 + - gdown==5.2.0 + - gin-config==0.5.0 + - gitdb==4.0.12 + - gitpython==3.1.44 + - grpcio==1.71.0 + - gsplat==1.5.0 + - h11==0.14.0 + - h5py==3.13.0 + - httpcore==1.0.8 + - httpx==0.28.1 + - huggingface-hub==0.25.2 + - idna==3.10 + - imageio==2.37.0 + - imageio-ffmpeg==0.6.0 + - importlib-metadata==8.6.1 + - ipykernel==6.29.5 + - ipython==8.35.0 + - ipywidgets==8.1.6 + - isoduration==20.11.0 + - itsdangerous==2.2.0 + - jaxtyping==0.3.1 + - jedi==0.19.2 + - jinja2==3.1.6 + - joblib==1.4.2 + - json5==0.12.0 + - jsonpointer==3.0.0 + - jsonschema==4.23.0 + - jsonschema-specifications==2024.10.1 + - jupyter==1.1.1 + - jupyter-client==8.6.3 + - jupyter-console==6.6.3 + - jupyter-core==5.7.2 + - jupyter-events==0.12.0 + - jupyter-lsp==2.2.5 + - jupyter-server==2.15.0 + - jupyter-server-terminals==0.5.3 + - jupyterlab==4.4.0 + - jupyterlab-pygments==0.3.0 + - jupyterlab-server==2.27.3 + - jupyterlab-widgets==3.0.14 + - kiwisolver==1.4.8 + - lazy-loader==0.4 + - lightning-utilities==0.14.3 + - lxml==5.3.2 + - manifold3d==3.0.1 + - mapbox-earcut==1.0.3 + - markdown==3.8 + - markdown-it-py==3.0.0 + - markupsafe==3.0.2 + - matplotlib==3.10.1 + - matplotlib-inline==0.1.7 + - mdurl==0.1.2 + - mediapy==1.2.2 + - mistune==3.1.3 + - mpmath==1.3.0 + - msgpack==1.1.0 + - msgpack-numpy==0.4.8 + - msgspec==0.19.0 + - msvc-runtime==14.42.34433 + - multiprocess==0.70.17 + - narwhals==1.34.1 + - nbclient==0.10.2 + - nbconvert==7.16.6 + - nbformat==5.10.4 + - nerfacc==0.5.3 + - nerfstudio==1.1.5 + - nest-asyncio==1.6.0 + - networkx==3.4.2 + - ninja==1.11.1.4 + - nodeenv==1.9.1 + - notebook==7.4.0 + - notebook-shim==0.2.4 + - numpy==1.26.4 + - nuscenes-devkit==1.1.9 + - open3d==0.19.0 + - opencv-contrib-python==4.11.0.86 + - opencv-python==4.11.0.86 + - opencv-python-headless==4.10.0.84 + - overrides==7.7.0 + - packaging==24.2 + - pandas==2.2.3 + - pandocfilters==1.5.1 + - parso==0.8.4 + - pathos==0.3.3 + - pillow==11.1.0 + - pip==25.0.1 + - platformdirs==4.3.7 + - plotly==6.0.1 + - plyfile==1.1 + - pox==0.3.5 + - ppft==1.7.6.9 + - prometheus-client==0.21.1 + - prompt-toolkit==3.0.50 + - protobuf==3.20.3 + - psutil==7.0.0 + - pure-eval==0.2.3 + - pycocotools==2.0.8 + - pycollada==0.9 + - pycparser==2.22 + - pydantic==2.11.3 + - pydantic-core==2.33.1 + - pygments==2.19.1 + - pymeshlab==2023.12.post1 + - pyngrok==7.2.3 + - pyparsing==3.2.3 + - pyquaternion==0.9.9 + - pysocks==1.7.1 + - python-box==6.1.0 + - python-dateutil==2.9.0.post0 + - python-engineio==4.11.2 + - python-json-logger==3.3.0 + - python-socketio==5.12.1 + - pytorch-msssim==1.0.0 + - pytz==2025.2 + - pywin32==310 + - pywinpty==2.0.15 + - pyyaml==6.0.2 + - pyzmq==26.4.0 + - rawpy==0.24.0 + - referencing==0.36.2 + - regex==2024.11.6 + - requests==2.32.3 + - requests-toolbelt==1.0.0 + - retrying==1.3.4 + - rfc3339-validator==0.1.4 + - rfc3986-validator==0.1.1 + - rich==14.0.0 + - rpds-py==0.24.0 + - rtree==1.4.0 + - scikit-image==0.25.2 + - scikit-learn==1.6.1 + - scipy==1.15.2 + - semantic-version==2.10.0 + - send2trash==1.8.3 + - sentencepiece==0.1.99 + - sentry-sdk==2.25.1 + - setproctitle==1.3.5 + - setuptools==78.1.0 + - shapely==2.1.0 + - shtab==1.7.1 + - simple-websocket==1.1.0 + - simplejson==3.20.1 + - six==1.17.0 + - smmap==5.0.2 + - sniffio==1.3.1 + - soupsieve==2.6 + - splatfacto-w==0.1.5 + - splines==0.3.0 + - stack-data==0.6.3 + - svg-path==6.3 + - sympy==1.13.3 + - tensorboard==2.19.0 + - tensorboard-data-server==0.7.2 + - tensorboardx==2.6.2.2 + - tensorly==0.9.0 + - termcolor==3.0.1 + - terminado==0.18.1 + - threadpoolctl==3.6.0 + - tifffile==2025.3.30 + - timm==0.6.7 + - tinycss2==1.4.0 + - tinycudann==1.7 + - tokenizers==0.13.3 + - tomli==2.2.1 + - torch==2.1.2+cu118 + - torch-fidelity==0.3.0 + - torch-scatter==2.1.2 + - torchmetrics==1.7.1 + - torchvision==0.16.2+cu118 + - tornado==6.4.2 + - tqdm==4.67.1 + - traitlets==5.14.3 + - transformers==4.29.2 + - trimesh==4.6.6 + - typeguard==4.4.2 + - types-python-dateutil==2.9.0.20241206 + - typing-extensions==4.13.2 + - typing-inspection==0.4.0 + - tyro==0.8.12 + - tzdata==2025.2 + - uri-template==1.3.0 + - urllib3==2.4.0 + - vhacdx==0.0.8.post2 + - viser==0.2.7 + - wadler-lindig==0.1.4 + - wandb==0.19.9 + - wcwidth==0.2.13 + - webcolors==24.11.1 + - webencodings==0.5.1 + - websocket-client==1.8.0 + - websockets==15.0.1 + - werkzeug==3.0.6 + - widgetsnbextension==4.0.14 + - wrapt==1.17.2 + - wsproto==1.2.0 + - wurlitzer==3.1.1 + - xatlas==0.0.10 + - xxhash==3.5.0 + - yourdfpy==0.0.57 + - zipnerf==0.1.0 + - zipp==3.21.0 +prefix: C:\Users\crist\anaconda3\envs\nerfstudio_test diff --git a/requirements_post_zipnerf - Copia.txt b/requirements_post_zipnerf - Copia.txt new file mode 100644 index 0000000000..284b87b139 --- /dev/null +++ b/requirements_post_zipnerf - Copia.txt @@ -0,0 +1,253 @@ +absl-py==2.2.2 +accelerate==0.19.0 +annotated-types==0.7.0 +anyio==4.9.0 +appdirs==1.4.4 +argon2-cffi==23.1.0 +argon2-cffi-bindings==21.2.0 +arrow==1.3.0 +asttokens==3.0.0 +async-lru==2.0.5 +attrs==25.3.0 +av==14.3.0 +babel==2.17.0 +beautifulsoup4==4.13.3 +bidict==0.23.1 +bitsandbytes==0.43.0 +bleach==6.2.0 +blinker==1.9.0 +cachetools==5.5.2 +certifi==2025.1.31 +cffi==1.17.1 +charset-normalizer==3.4.1 +click==8.1.8 +colorama==0.4.6 +colorlog==6.9.0 +comet_ml==3.49.7 +comm==0.2.2 +ConfigArgParse==1.7 +configobj==5.0.9 +contourpy==1.3.1 +cryptography==44.0.2 +cuda_backend==0.0.0 +cycler==0.12.1 +dash==3.0.2 +debugpy==1.8.14 +decorator==5.2.1 +defusedxml==0.7.1 +descartes==1.1.0 +diffusers==0.16.1 +dill==0.3.9 +docker-pycreds==0.4.0 +docstring_parser==0.16 +dulwich==0.22.8 +everett==3.1.0 +exceptiongroup==1.2.2 +executing==2.2.0 +fastjsonschema==2.21.1 +filelock==3.18.0 +fire==0.7.0 +Flask==3.0.3 +fonttools==4.57.0 +fpsample==0.3.3 +fqdn==1.5.1 +fsspec==2025.3.2 +gdown==5.2.0 +gin-config==0.5.0 +gitdb==4.0.12 +GitPython==3.1.44 +grpcio==1.71.0 +gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@d23d7ca5dd26c3756967304b621ae88521672ed5 +h11==0.14.0 +h5py==3.13.0 +httpcore==1.0.8 +httpx==0.28.1 +huggingface-hub==0.25.2 +idna==3.10 +imageio==2.37.0 +imageio-ffmpeg==0.6.0 +importlib_metadata==8.6.1 +ipykernel==6.29.5 +ipython==8.35.0 +ipywidgets==8.1.6 +isoduration==20.11.0 +itsdangerous==2.2.0 +jaxtyping==0.3.1 +jedi==0.19.2 +Jinja2==3.1.6 +joblib==1.4.2 +json5==0.12.0 +jsonpointer==3.0.0 +jsonschema==4.23.0 +jsonschema-specifications==2024.10.1 +jupyter==1.1.1 +jupyter-console==6.6.3 +jupyter-events==0.12.0 +jupyter-lsp==2.2.5 +jupyter_client==8.6.3 +jupyter_core==5.7.2 +jupyter_server==2.15.0 +jupyter_server_terminals==0.5.3 +jupyterlab==4.4.0 +jupyterlab_pygments==0.3.0 +jupyterlab_server==2.27.3 +jupyterlab_widgets==3.0.14 +kiwisolver==1.4.8 +lazy_loader==0.4 +lightning-utilities==0.14.3 +lxml==5.3.2 +manifold3d==3.0.1 +mapbox_earcut==1.0.3 +Markdown==3.8 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +matplotlib==3.10.1 +matplotlib-inline==0.1.7 +mdurl==0.1.2 +mediapy==1.2.2 +mistune==3.1.3 +mpmath==1.3.0 +msgpack==1.1.0 +msgpack-numpy==0.4.8 +msgspec==0.19.0 +msvc_runtime==14.42.34433 +multiprocess==0.70.17 +narwhals==1.34.1 +nbclient==0.10.2 +nbconvert==7.16.6 +nbformat==5.10.4 +nerfacc @ git+https://github.com/nerfstudio-project/nerfacc.git@57ccfa14feb94975836ea6913149a86737220f2b +nerfstudio==1.1.5 +nest-asyncio==1.6.0 +networkx==3.4.2 +ninja==1.11.1.4 +nodeenv==1.9.1 +notebook==7.4.0 +notebook_shim==0.2.4 +numpy==1.26.4 +nuscenes-devkit==1.1.9 +open3d==0.19.0 +opencv-contrib-python==4.11.0.86 +opencv-python==4.11.0.86 +opencv-python-headless==4.10.0.84 +overrides==7.7.0 +packaging==24.2 +pandas==2.2.3 +pandocfilters==1.5.1 +parso==0.8.4 +pathos==0.3.3 +pillow==11.1.0 +platformdirs==4.3.7 +plotly==6.0.1 +plyfile==1.1 +pox==0.3.5 +ppft==1.7.6.9 +prometheus_client==0.21.1 +prompt_toolkit==3.0.50 +protobuf==3.20.3 +psutil==7.0.0 +pure_eval==0.2.3 +pycocotools==2.0.8 +pycollada==0.9 +pycparser==2.22 +pydantic==2.11.3 +pydantic_core==2.33.1 +Pygments==2.19.1 +pymeshlab==2023.12.post1 +pyngrok==7.2.3 +pyparsing==3.2.3 +pyquaternion==0.9.9 +PySocks==1.7.1 +python-box==6.1.0 +python-dateutil==2.9.0.post0 +python-engineio==4.11.2 +python-json-logger==3.3.0 +python-socketio==5.12.1 +pytorch-msssim==1.0.0 +pytz==2025.2 +pywin32==310 +pywinpty==2.0.15 +PyYAML==6.0.2 +pyzmq==26.4.0 +rawpy==0.24.0 +referencing==0.36.2 +regex==2024.11.6 +requests==2.32.3 +requests-toolbelt==1.0.0 +retrying==1.3.4 +rfc3339-validator==0.1.4 +rfc3986-validator==0.1.1 +rich==14.0.0 +rpds-py==0.24.0 +rtree==1.4.0 +scikit-image==0.25.2 +scikit-learn==1.6.1 +scipy==1.15.2 +semantic-version==2.10.0 +Send2Trash==1.8.3 +sentencepiece==0.1.99 +sentry-sdk==2.25.1 +setproctitle==1.3.5 +shapely==2.1.0 +shtab==1.7.1 +simple-websocket==1.1.0 +simplejson==3.20.1 +six==1.17.0 +smmap==5.0.2 +sniffio==1.3.1 +soupsieve==2.6 +splatfacto-w @ git+https://github.com/KevinXu02/splatfacto-w@119a3bfb3aa03669278e174ff11c4dfdcbcf97d7 +splines==0.3.0 +stack-data==0.6.3 +svg.path==6.3 +sympy==1.13.3 +tensorboard==2.19.0 +tensorboard-data-server==0.7.2 +tensorboardX==2.6.2.2 +tensorly==0.9.0 +termcolor==3.0.1 +terminado==0.18.1 +threadpoolctl==3.6.0 +tifffile==2025.3.30 +timm==0.6.7 +tinycss2==1.4.0 +tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@075158a70b87dba8729188a9cadc9411cfa4b71d#subdirectory=bindings/torch +tokenizers==0.13.3 +tomli==2.2.1 +torch==2.1.2+cu118 +torch-fidelity==0.3.0 +torch_scatter==2.1.2 +torchmetrics==1.7.1 +torchvision==0.16.2+cu118 +tornado==6.4.2 +tqdm==4.67.1 +traitlets==5.14.3 +transformers==4.29.2 +trimesh==4.6.6 +typeguard==4.4.2 +types-python-dateutil==2.9.0.20241206 +typing-inspection==0.4.0 +typing_extensions==4.13.2 +tyro==0.8.12 +tzdata==2025.2 +uri-template==1.3.0 +urllib3==2.4.0 +vhacdx==0.0.8.post2 +viser==0.2.7 +wadler_lindig==0.1.4 +wandb==0.19.9 +wcwidth==0.2.13 +webcolors==24.11.1 +webencodings==0.5.1 +websocket-client==1.8.0 +websockets==15.0.1 +Werkzeug==3.0.6 +widgetsnbextension==4.0.14 +wrapt==1.17.2 +wsproto==1.2.0 +wurlitzer==3.1.1 +xatlas==0.0.10 +xxhash==3.5.0 +yourdfpy==0.0.57 +-e git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git@e081caeb81473fac6f057ceb2e560207b4ba5112#egg=zipnerf +zipp==3.21.0 diff --git a/requirements_post_zipnerf.txt b/requirements_post_zipnerf.txt new file mode 100644 index 0000000000..096495458c --- /dev/null +++ b/requirements_post_zipnerf.txt @@ -0,0 +1,251 @@ +absl-py==2.2.2 +accelerate==0.19.0 +annotated-types==0.7.0 +anyio==4.9.0 +appdirs==1.4.4 +argon2-cffi==23.1.0 +argon2-cffi-bindings==21.2.0 +arrow==1.3.0 +asttokens==3.0.0 +async-lru==2.0.5 +attrs==25.3.0 +av==14.3.0 +babel==2.17.0 +beautifulsoup4==4.13.3 +bidict==0.23.1 +bitsandbytes==0.43.0 +bleach==6.2.0 +blinker==1.9.0 +cachetools==5.5.2 +certifi==2025.1.31 +cffi==1.17.1 +charset-normalizer==3.4.1 +click==8.1.8 +colorama==0.4.6 +colorlog==6.9.0 +comet_ml==3.49.7 +comm==0.2.2 +ConfigArgParse==1.7 +configobj==5.0.9 +contourpy==1.3.1 +cryptography==44.0.2 +cuda_backend==0.0.0 +cycler==0.12.1 +dash==3.0.2 +debugpy==1.8.14 +decorator==5.2.1 +defusedxml==0.7.1 +descartes==1.1.0 +diffusers==0.16.1 +dill==0.3.9 +docker-pycreds==0.4.0 +docstring_parser==0.16 +dulwich==0.22.8 +everett==3.1.0 +exceptiongroup==1.2.2 +executing==2.2.0 +fastjsonschema==2.21.1 +filelock==3.18.0 +fire==0.7.0 +Flask==3.0.3 +fonttools==4.57.0 +fpsample==0.3.3 +fqdn==1.5.1 +fsspec==2025.3.2 +gdown==5.2.0 +gin-config==0.5.0 +gitdb==4.0.12 +GitPython==3.1.44 +grpcio==1.71.0 +h11==0.14.0 +h5py==3.13.0 +httpcore==1.0.8 +httpx==0.28.1 +huggingface-hub==0.25.2 +idna==3.10 +imageio==2.37.0 +imageio-ffmpeg==0.6.0 +importlib_metadata==8.6.1 +ipykernel==6.29.5 +ipython==8.35.0 +ipywidgets==8.1.6 +isoduration==20.11.0 +itsdangerous==2.2.0 +jaxtyping==0.3.1 +jedi==0.19.2 +Jinja2==3.1.6 +joblib==1.4.2 +json5==0.12.0 +jsonpointer==3.0.0 +jsonschema==4.23.0 +jsonschema-specifications==2024.10.1 +jupyter==1.1.1 +jupyter-console==6.6.3 +jupyter-events==0.12.0 +jupyter-lsp==2.2.5 +jupyter_client==8.6.3 +jupyter_core==5.7.2 +jupyter_server==2.15.0 +jupyter_server_terminals==0.5.3 +jupyterlab==4.4.0 +jupyterlab_pygments==0.3.0 +jupyterlab_server==2.27.3 +jupyterlab_widgets==3.0.14 +kiwisolver==1.4.8 +lazy_loader==0.4 +lightning-utilities==0.14.3 +lxml==5.3.2 +manifold3d==3.0.1 +mapbox_earcut==1.0.3 +Markdown==3.8 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +matplotlib==3.10.1 +matplotlib-inline==0.1.7 +mdurl==0.1.2 +mediapy==1.2.2 +mistune==3.1.3 +mpmath==1.3.0 +msgpack==1.1.0 +msgpack-numpy==0.4.8 +msgspec==0.19.0 +msvc_runtime==14.42.34433 +multiprocess==0.70.17 +narwhals==1.34.1 +nbclient==0.10.2 +nbconvert==7.16.6 +nbformat==5.10.4 +nerfstudio==1.1.5 +nest-asyncio==1.6.0 +networkx==3.4.2 +ninja==1.11.1.4 +nodeenv==1.9.1 +notebook==7.4.0 +notebook_shim==0.2.4 +numpy==1.26.4 +nuscenes-devkit==1.1.9 +open3d==0.19.0 +opencv-contrib-python==4.11.0.86 +opencv-python==4.11.0.86 +opencv-python-headless==4.10.0.84 +overrides==7.7.0 +packaging==24.2 +pandas==2.2.3 +pandocfilters==1.5.1 +parso==0.8.4 +pathos==0.3.3 +pillow==11.1.0 +platformdirs==4.3.7 +plotly==6.0.1 +plyfile==1.1 +pox==0.3.5 +ppft==1.7.6.9 +prometheus_client==0.21.1 +prompt_toolkit==3.0.50 +protobuf==3.20.3 +psutil==7.0.0 +pure_eval==0.2.3 +pycocotools==2.0.8 +pycollada==0.9 +pycparser==2.22 +pydantic==2.11.3 +pydantic_core==2.33.1 +Pygments==2.19.1 +pymeshlab==2023.12.post1 +pyngrok==7.2.3 +pyparsing==3.2.3 +pyquaternion==0.9.9 +PySocks==1.7.1 +python-box==6.1.0 +python-dateutil==2.9.0.post0 +python-engineio==4.11.2 +python-json-logger==3.3.0 +python-socketio==5.12.1 +pytorch-msssim==1.0.0 +pytz==2025.2 +pywin32==310 +pywinpty==2.0.15 +PyYAML==6.0.2 +pyzmq==26.4.0 +rawpy==0.24.0 +referencing==0.36.2 +regex==2024.11.6 +requests==2.32.3 +requests-toolbelt==1.0.0 +retrying==1.3.4 +rfc3339-validator==0.1.4 +rfc3986-validator==0.1.1 +rich==14.0.0 +rpds-py==0.24.0 +rtree==1.4.0 +scikit-image==0.25.2 +scikit-learn==1.6.1 +scipy==1.15.2 +semantic-version==2.10.0 +Send2Trash==1.8.3 +sentencepiece==0.1.99 +sentry-sdk==2.25.1 +setproctitle==1.3.5 +shapely==2.1.0 +shtab==1.7.1 +simple-websocket==1.1.0 +simplejson==3.20.1 +six==1.17.0 +smmap==5.0.2 +sniffio==1.3.1 +soupsieve==2.6 +splatfacto-w @ git+https://github.com/KevinXu02/splatfacto-w@119a3bfb3aa03669278e174ff11c4dfdcbcf97d7 +splines==0.3.0 +stack-data==0.6.3 +svg.path==6.3 +sympy==1.13.3 +tensorboard==2.19.0 +tensorboard-data-server==0.7.2 +tensorboardX==2.6.2.2 +tensorly==0.9.0 +termcolor==3.0.1 +terminado==0.18.1 +threadpoolctl==3.6.0 +tifffile==2025.3.30 +timm==0.6.7 +tinycss2==1.4.0 +tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@075158a70b87dba8729188a9cadc9411cfa4b71d#subdirectory=bindings/torch +tokenizers==0.13.3 +tomli==2.2.1 +torch==2.1.2+cu118 +torch-fidelity==0.3.0 +torch_scatter==2.1.2 +torchmetrics==1.7.1 +torchvision==0.16.2+cu118 +tornado==6.4.2 +tqdm==4.67.1 +traitlets==5.14.3 +transformers==4.29.2 +trimesh==4.6.6 +typeguard==4.4.2 +types-python-dateutil==2.9.0.20241206 +typing-inspection==0.4.0 +typing_extensions==4.13.2 +tyro==0.8.12 +tzdata==2025.2 +uri-template==1.3.0 +urllib3==2.4.0 +vhacdx==0.0.8.post2 +viser==0.2.7 +wadler_lindig==0.1.4 +wandb==0.19.9 +wcwidth==0.2.13 +webcolors==24.11.1 +webencodings==0.5.1 +websocket-client==1.8.0 +websockets==15.0.1 +Werkzeug==3.0.6 +widgetsnbextension==4.0.14 +wrapt==1.17.2 +wsproto==1.2.0 +wurlitzer==3.1.1 +xatlas==0.0.10 +xxhash==3.5.0 +yourdfpy==0.0.57 +-e git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git@e081caeb81473fac6f057ceb2e560207b4ba5112#egg=zipnerf +zipp==3.21.0 From 9688a3d62a0823d03c5ec08ade1c5f249bbe1a02 Mon Sep 17 00:00:00 2001 From: Francesco Christopher Date: Thu, 8 Jan 2026 21:58:45 +0100 Subject: [PATCH 2/8] cleanup --- .gitignore | 6 +- base.bat | 50 ++++++ extras.bat | 60 +++++++ requirements_conda.yaml | 319 ++++++++++++++++++++++++++++++++++ requirements_pip.txt | 253 +++++++++++++++++++++++++++ requirements_post_zipnerf.txt | 2 + test_cli.py | 86 +++++++++ 7 files changed, 773 insertions(+), 3 deletions(-) create mode 100644 base.bat create mode 100644 extras.bat create mode 100644 requirements_conda.yaml create mode 100644 requirements_pip.txt create mode 100644 test_cli.py diff --git a/.gitignore b/.gitignore index f2f95b5401..a85e0412e7 100644 --- a/.gitignore +++ b/.gitignore @@ -129,6 +129,7 @@ venv/ ENV/ env.bak/ venv.bak/ +.nerfstudio.code-workspace # Spyder project settings .spyderproject @@ -196,9 +197,8 @@ camera_paths/ /*.yaml # ✅ Exceptions: Include specific files in root dir -!requirements_post_zipnerf.txt -!requirements_post_zipnerf - Copia.txt -!nerfstudio_stable_environment_post_zipnerf.yaml +!requirements_pip.txt +!requirements_conda.yaml # External Submodules: NeRFtoGSandBack/ glomap/ diff --git a/base.bat b/base.bat new file mode 100644 index 0000000000..a0a3a2a6ad --- /dev/null +++ b/base.bat @@ -0,0 +1,50 @@ +@echo off +setlocal enabledelayedexpansion + +REM ==== CONFIG ==== +set ENV_NAME=nerfstudio +set YAML_FILE=nerfstudio_stable_environment_post_zipnerf.yaml +set REQUIREMENTS=requirements_post_zipnerf.txt +set PYTHON_EXE=python + +echo. +echo === Nerfstudio Base Installer === +echo. + +REM === Choose install mode === +choice /C CVP /M "Choose environment type: (C)onda, (V)env, or (P)reinstalled python?" +if errorlevel 3 set INSTALL_MODE=PYTHON +if errorlevel 2 set INSTALL_MODE=VENV +if errorlevel 1 set INSTALL_MODE=CONDA + +REM === Setup environment === +if "%INSTALL_MODE%"=="CONDA" ( + choice /C YN /M "Use YAML file? (Y=yes, N=use requirements.txt)" + if errorlevel 2 ( + echo Creating conda env from pip reqs... + conda create -y -n %ENV_NAME% python=3.10 + call conda activate %ENV_NAME% + pip install -r %REQUIREMENTS% + ) else ( + echo Creating conda env from YAML... + conda env create -f %YAML_FILE% + call conda activate %ENV_NAME% + ) +) else if "%INSTALL_MODE%"=="VENV" ( + echo Creating venv... + %PYTHON_EXE% -m venv %ENV_NAME% + call %ENV_NAME%\Scripts\activate + pip install -r %REQUIREMENTS% +) else ( + echo Using system-installed Python... + pip install -r %REQUIREMENTS% +) + +REM === Nerfstudio CLI === +pip install nerfstudio +call ns-install-cli + +echo. +echo ✅ Base Nerfstudio environment ready. +echo Run extras.bat to install optional modules. +pause diff --git a/extras.bat b/extras.bat new file mode 100644 index 0000000000..2c2277cf5f --- /dev/null +++ b/extras.bat @@ -0,0 +1,60 @@ +@echo off +setlocal enabledelayedexpansion + +REM ==== Optional modules config ==== +set MODULES=zipnerf-pytorch sdfstudio splatfacto-w NeRFtoGSandBack opennerf instruct-gs2gs +set FLAG_REFRESH_CLI=0 + +echo. +echo === Nerfstudio Optional Module Installer === +echo. + +REM === CUDA / TORCH INFO === +echo Detecting CUDA + Torch info... +python -c "import torch; print(f'Torch: {torch.__version__}, CUDA: {torch.version.cuda}, Available: {torch.cuda.is_available()}')" +echo. + +REM === Iterate modules === +for %%M in (%MODULES%) do ( + choice /C YN /M "Install %%M? (Y/N)" + if errorlevel 1 ( + if not exist %%M ( + if "%%M"=="zipnerf-pytorch" ( + git clone https://github.com/SuLvXiangXin/zipnerf-pytorch.git + cd zipnerf-pytorch + pip install -r requirements.txt + pip install ./extensions/cuda + if not exist nvdiffrast ( + git clone https://github.com/NVlabs/nvdiffrast + pip install ./nvdiffrast + ) + set CUDA=cu118 + pip install torch-scatter -f https://data.pyg.org/whl/torch-2.1.0+%CUDA%.html + cd .. + ) else if "%%M"=="splatfacto-w" ( + git clone https://github.com/KevinXu02/splatfacto-w + pip install -e splatfacto-w + ) else if "%%M"=="sdfstudio" ( + git clone https://github.com/autonomousvision/sdfstudio.git + pip install -e sdfstudio + ) else if "%%M"=="NeRFtoGSandBack" ( + git clone https://github.com/grasp-lyrl/NeRFtoGSandBack + ) else if "%%M"=="opennerf" ( + git clone https://github.com/opennerf/opennerf + ) else if "%%M"=="instruct-gs2gs" ( + git clone https://github.com/cvachha/instruct-gs2gs + pip install git+https://github.com/cvachha/instruct-gs2gs + ) + ) + set FLAG_REFRESH_CLI=1 + ) +) + +if %FLAG_REFRESH_CLI%==1 ( + echo Refreshing Nerfstudio CLI... + call ns-install-cli +) + +echo. +echo ✅ Optional module setup complete. +pause diff --git a/requirements_conda.yaml b/requirements_conda.yaml new file mode 100644 index 0000000000..91fb5ad9d7 --- /dev/null +++ b/requirements_conda.yaml @@ -0,0 +1,319 @@ +name: nerfstudio_test +channels: + - nvidia/label/cuda-11.8.0 + - defaults + - https://repo.anaconda.com/pkgs/main + - https://repo.anaconda.com/pkgs/r + - https://repo.anaconda.com/pkgs/msys2 +dependencies: + - bzip2=1.0.8=h2bbff1b_6 + - ca-certificates=2025.2.25=haa95532_0 + - cuda-cccl=11.8.89=0 + - cuda-command-line-tools=11.8.0=0 + - cuda-compiler=11.8.0=0 + - cuda-cudart=11.8.89=0 + - cuda-cudart-dev=11.8.89=0 + - cuda-cuobjdump=11.8.86=0 + - cuda-cupti=11.8.87=0 + - cuda-cuxxfilt=11.8.86=0 + - cuda-documentation=11.8.86=0 + - cuda-libraries=11.8.0=0 + - cuda-libraries-dev=11.8.0=0 + - cuda-memcheck=11.8.86=0 + - cuda-nsight-compute=11.8.0=0 + - cuda-nvcc=11.8.89=0 + - cuda-nvdisasm=11.8.86=0 + - cuda-nvml-dev=11.8.86=0 + - cuda-nvprof=11.8.87=0 + - cuda-nvprune=11.8.86=0 + - cuda-nvrtc=11.8.89=0 + - cuda-nvrtc-dev=11.8.89=0 + - cuda-nvtx=11.8.86=0 + - cuda-nvvp=11.8.87=0 + - cuda-profiler-api=11.8.86=0 + - cuda-sanitizer-api=11.8.86=0 + - cuda-toolkit=11.8.0=0 + - cuda-tools=11.8.0=0 + - cuda-visual-tools=11.8.0=0 + - libcublas=11.11.3.6=0 + - libcublas-dev=11.11.3.6=0 + - libcufft=10.9.0.58=0 + - libcufft-dev=10.9.0.58=0 + - libcurand=10.3.0.86=0 + - libcurand-dev=10.3.0.86=0 + - libcusolver=11.4.1.48=0 + - libcusolver-dev=11.4.1.48=0 + - libcusparse=11.7.5.86=0 + - libcusparse-dev=11.7.5.86=0 + - libffi=3.4.4=hd77b12b_1 + - libnpp=11.8.0.86=0 + - libnpp-dev=11.8.0.86=0 + - libnvjpeg=11.9.0.86=0 + - libnvjpeg-dev=11.9.0.86=0 + - nsight-compute=2022.3.0.22=0 + - openssl=3.0.16=h3f729d1_0 + - python=3.10.16=h4607a30_1 + - sqlite=3.45.3=h2bbff1b_0 + - tk=8.6.14=h0416ee5_0 + - vc=14.42=haa95532_4 + - vs2015_runtime=14.42.34433=he0abc0d_4 + - wheel=0.45.1=py310haa95532_0 + - xz=5.6.4=h4754444_1 + - zlib=1.2.13=h8cc25b3_1 + - pip: + - absl-py==2.2.2 + - accelerate==0.19.0 + - annotated-types==0.7.0 + - anyio==4.9.0 + - appdirs==1.4.4 + - argon2-cffi==23.1.0 + - argon2-cffi-bindings==21.2.0 + - arrow==1.3.0 + - asttokens==3.0.0 + - async-lru==2.0.5 + - attrs==25.3.0 + - av==14.3.0 + - babel==2.17.0 + - beautifulsoup4==4.13.3 + - bidict==0.23.1 + - bitsandbytes==0.43.0 + - bleach==6.2.0 + - blinker==1.9.0 + - cachetools==5.5.2 + - certifi==2025.1.31 + - cffi==1.17.1 + - charset-normalizer==3.4.1 + - click==8.1.8 + - colorama==0.4.6 + - colorlog==6.9.0 + - comet-ml==3.49.7 + - comm==0.2.2 + - configargparse==1.7 + - configobj==5.0.9 + - contourpy==1.3.1 + - cryptography==44.0.2 + - cuda-backend==0.0.0 + - cycler==0.12.1 + - dash==3.0.2 + - debugpy==1.8.14 + - decorator==5.2.1 + - defusedxml==0.7.1 + - descartes==1.1.0 + - diffusers==0.16.1 + - dill==0.3.9 + - docker-pycreds==0.4.0 + - docstring-parser==0.16 + - dulwich==0.22.8 + - everett==3.1.0 + - exceptiongroup==1.2.2 + - executing==2.2.0 + - fastjsonschema==2.21.1 + - filelock==3.18.0 + - fire==0.7.0 + - flask==3.0.3 + - fonttools==4.57.0 + - fpsample==0.3.3 + - fqdn==1.5.1 + - fsspec==2025.3.2 + - gdown==5.2.0 + - gin-config==0.5.0 + - gitdb==4.0.12 + - gitpython==3.1.44 + - grpcio==1.71.0 + - gsplat==1.5.0 + - h11==0.14.0 + - h5py==3.13.0 + - httpcore==1.0.8 + - httpx==0.28.1 + - huggingface-hub==0.25.2 + - idna==3.10 + - imageio==2.37.0 + - imageio-ffmpeg==0.6.0 + - importlib-metadata==8.6.1 + - ipykernel==6.29.5 + - ipython==8.35.0 + - ipywidgets==8.1.6 + - isoduration==20.11.0 + - itsdangerous==2.2.0 + - jaxtyping==0.3.1 + - jedi==0.19.2 + - jinja2==3.1.6 + - joblib==1.4.2 + - json5==0.12.0 + - jsonpointer==3.0.0 + - jsonschema==4.23.0 + - jsonschema-specifications==2024.10.1 + - jupyter==1.1.1 + - jupyter-client==8.6.3 + - jupyter-console==6.6.3 + - jupyter-core==5.7.2 + - jupyter-events==0.12.0 + - jupyter-lsp==2.2.5 + - jupyter-server==2.15.0 + - jupyter-server-terminals==0.5.3 + - jupyterlab==4.4.0 + - jupyterlab-pygments==0.3.0 + - jupyterlab-server==2.27.3 + - jupyterlab-widgets==3.0.14 + - kiwisolver==1.4.8 + - lazy-loader==0.4 + - lightning-utilities==0.14.3 + - lxml==5.3.2 + - manifold3d==3.0.1 + - mapbox-earcut==1.0.3 + - markdown==3.8 + - markdown-it-py==3.0.0 + - markupsafe==3.0.2 + - matplotlib==3.10.1 + - matplotlib-inline==0.1.7 + - mdurl==0.1.2 + - mediapy==1.2.2 + - mistune==3.1.3 + - mpmath==1.3.0 + - msgpack==1.1.0 + - msgpack-numpy==0.4.8 + - msgspec==0.19.0 + - msvc-runtime==14.42.34433 + - multiprocess==0.70.17 + - narwhals==1.34.1 + - nbclient==0.10.2 + - nbconvert==7.16.6 + - nbformat==5.10.4 + - nerfacc==0.5.3 + - nerfstudio==1.1.5 + - nest-asyncio==1.6.0 + - networkx==3.4.2 + - ninja==1.11.1.4 + - nodeenv==1.9.1 + - notebook==7.4.0 + - notebook-shim==0.2.4 + - numpy==1.26.4 + - nuscenes-devkit==1.1.9 + - open3d==0.19.0 + - opencv-contrib-python==4.11.0.86 + - opencv-python==4.11.0.86 + - opencv-python-headless==4.10.0.84 + - overrides==7.7.0 + - packaging==24.2 + - pandas==2.2.3 + - pandocfilters==1.5.1 + - parso==0.8.4 + - pathos==0.3.3 + - pillow==11.1.0 + - pip==25.0.1 + - platformdirs==4.3.7 + - plotly==6.0.1 + - plyfile==1.1 + - pox==0.3.5 + - ppft==1.7.6.9 + - prometheus-client==0.21.1 + - prompt-toolkit==3.0.50 + - protobuf==3.20.3 + - psutil==7.0.0 + - pure-eval==0.2.3 + - pycocotools==2.0.8 + - pycollada==0.9 + - pycparser==2.22 + - pydantic==2.11.3 + - pydantic-core==2.33.1 + - pygments==2.19.1 + - pymeshlab==2023.12.post1 + - pyngrok==7.2.3 + - pyparsing==3.2.3 + - pyquaternion==0.9.9 + - pysocks==1.7.1 + - python-box==6.1.0 + - python-dateutil==2.9.0.post0 + - python-engineio==4.11.2 + - python-json-logger==3.3.0 + - python-socketio==5.12.1 + - pytorch-msssim==1.0.0 + - pytz==2025.2 + - pywin32==310 + - pywinpty==2.0.15 + - pyyaml==6.0.2 + - pyzmq==26.4.0 + - rawpy==0.24.0 + - referencing==0.36.2 + - regex==2024.11.6 + - requests==2.32.3 + - requests-toolbelt==1.0.0 + - retrying==1.3.4 + - rfc3339-validator==0.1.4 + - rfc3986-validator==0.1.1 + - rich==14.0.0 + - rpds-py==0.24.0 + - rtree==1.4.0 + - scikit-image==0.25.2 + - scikit-learn==1.6.1 + - scipy==1.15.2 + - semantic-version==2.10.0 + - send2trash==1.8.3 + - sentencepiece==0.1.99 + - sentry-sdk==2.25.1 + - setproctitle==1.3.5 + - setuptools==78.1.0 + - shapely==2.1.0 + - shtab==1.7.1 + - simple-websocket==1.1.0 + - simplejson==3.20.1 + - six==1.17.0 + - smmap==5.0.2 + - sniffio==1.3.1 + - soupsieve==2.6 + - splatfacto-w==0.1.5 + - splines==0.3.0 + - stack-data==0.6.3 + - svg-path==6.3 + - sympy==1.13.3 + - tensorboard==2.19.0 + - tensorboard-data-server==0.7.2 + - tensorboardx==2.6.2.2 + - tensorly==0.9.0 + - termcolor==3.0.1 + - terminado==0.18.1 + - threadpoolctl==3.6.0 + - tifffile==2025.3.30 + - timm==0.6.7 + - tinycss2==1.4.0 + - tinycudann==1.7 + - tokenizers==0.13.3 + - tomli==2.2.1 + - torch==2.1.2+cu118 + - torch-fidelity==0.3.0 + - torch-scatter==2.1.2 + - torchmetrics==1.7.1 + - torchvision==0.16.2+cu118 + - tornado==6.4.2 + - tqdm==4.67.1 + - traitlets==5.14.3 + - transformers==4.29.2 + - trimesh==4.6.6 + - typeguard==4.4.2 + - types-python-dateutil==2.9.0.20241206 + - typing-extensions==4.13.2 + - typing-inspection==0.4.0 + - tyro==0.8.12 + - tzdata==2025.2 + - uri-template==1.3.0 + - urllib3==2.4.0 + - vhacdx==0.0.8.post2 + - viser==0.2.7 + - wadler-lindig==0.1.4 + - wandb==0.19.9 + - wcwidth==0.2.13 + - webcolors==24.11.1 + - webencodings==0.5.1 + - websocket-client==1.8.0 + - websockets==15.0.1 + - werkzeug==3.0.6 + - widgetsnbextension==4.0.14 + - wrapt==1.17.2 + - wsproto==1.2.0 + - wurlitzer==3.1.1 + - xatlas==0.0.10 + - xxhash==3.5.0 + - yourdfpy==0.0.57 + - zipnerf==0.1.0 + - zipp==3.21.0 +prefix: C:\Users\crist\anaconda3\envs\nerfstudio_test diff --git a/requirements_pip.txt b/requirements_pip.txt new file mode 100644 index 0000000000..05ae5e0508 --- /dev/null +++ b/requirements_pip.txt @@ -0,0 +1,253 @@ +absl-py==2.2.2 +accelerate==0.19.0 +annotated-types==0.7.0 +anyio==4.9.0 +appdirs==1.4.4 +argon2-cffi==23.1.0 +argon2-cffi-bindings==21.2.0 +arrow==1.3.0 +asttokens==3.0.0 +async-lru==2.0.5 +attrs==25.3.0 +av==14.3.0 +babel==2.17.0 +beautifulsoup4==4.13.3 +bidict==0.23.1 +bitsandbytes==0.43.0 +bleach==6.2.0 +blinker==1.9.0 +cachetools==5.5.2 +certifi==2025.1.31 +cffi==1.17.1 +charset-normalizer==3.4.1 +click==8.1.8 +colorama==0.4.6 +colorlog==6.9.0 +comet_ml==3.49.7 +comm==0.2.2 +ConfigArgParse==1.7 +configobj==5.0.9 +contourpy==1.3.1 +cryptography==44.0.2 +cuda_backend==0.0.0 +cycler==0.12.1 +dash==3.0.2 +debugpy==1.8.14 +decorator==5.2.1 +defusedxml==0.7.1 +descartes==1.1.0 +diffusers==0.16.1 +dill==0.3.9 +docker-pycreds==0.4.0 +docstring_parser==0.16 +dulwich==0.22.8 +everett==3.1.0 +exceptiongroup==1.2.2 +executing==2.2.0 +fastjsonschema==2.21.1 +filelock==3.18.0 +fire==0.7.0 +Flask==3.0.3 +fonttools==4.57.0 +fpsample==0.3.3 +fqdn==1.5.1 +fsspec==2025.3.2 +gdown==5.2.0 +gin-config==0.5.0 +gitdb==4.0.12 +GitPython==3.1.44 +grpcio==1.71.0 +h11==0.14.0 +h5py==3.13.0 +httpcore==1.0.8 +httpx==0.28.1 +huggingface-hub==0.25.2 +idna==3.10 +imageio==2.37.0 +imageio-ffmpeg==0.6.0 +importlib_metadata==8.6.1 +ipykernel==6.29.5 +ipython==8.35.0 +ipywidgets==8.1.6 +isoduration==20.11.0 +itsdangerous==2.2.0 +jaxtyping==0.3.1 +jedi==0.19.2 +Jinja2==3.1.6 +joblib==1.4.2 +json5==0.12.0 +jsonpointer==3.0.0 +jsonschema==4.23.0 +jsonschema-specifications==2024.10.1 +jupyter==1.1.1 +jupyter-console==6.6.3 +jupyter-events==0.12.0 +jupyter-lsp==2.2.5 +jupyter_client==8.6.3 +jupyter_core==5.7.2 +jupyter_server==2.15.0 +jupyter_server_terminals==0.5.3 +jupyterlab==4.4.0 +jupyterlab_pygments==0.3.0 +jupyterlab_server==2.27.3 +jupyterlab_widgets==3.0.14 +kiwisolver==1.4.8 +lazy_loader==0.4 +lightning-utilities==0.14.3 +lxml==5.3.2 +manifold3d==3.0.1 +mapbox_earcut==1.0.3 +Markdown==3.8 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +matplotlib==3.10.1 +matplotlib-inline==0.1.7 +mdurl==0.1.2 +mediapy==1.2.2 +mistune==3.1.3 +mpmath==1.3.0 +msgpack==1.1.0 +msgpack-numpy==0.4.8 +msgspec==0.19.0 +msvc_runtime==14.42.34433 +multiprocess==0.70.17 +narwhals==1.34.1 +nbclient==0.10.2 +nbconvert==7.16.6 +nbformat==5.10.4 +nerfstudio==1.1.5 +nest-asyncio==1.6.0 +networkx==3.4.2 +ninja==1.11.1.4 +nodeenv==1.9.1 +notebook==7.4.0 +notebook_shim==0.2.4 +numpy==1.26.4 +nuscenes-devkit==1.1.9 +open3d==0.19.0 +opencv-contrib-python==4.11.0.86 +opencv-python==4.11.0.86 +opencv-python-headless==4.10.0.84 +overrides==7.7.0 +packaging==24.2 +pandas==2.2.3 +pandocfilters==1.5.1 +parso==0.8.4 +pathos==0.3.3 +pillow==11.1.0 +platformdirs==4.3.7 +plotly==6.0.1 +plyfile==1.1 +pox==0.3.5 +ppft==1.7.6.9 +prometheus_client==0.21.1 +prompt_toolkit==3.0.50 +protobuf==3.20.3 +psutil==7.0.0 +pure_eval==0.2.3 +pycocotools==2.0.8 +pycollada==0.9 +pycparser==2.22 +pydantic==2.11.3 +pydantic_core==2.33.1 +Pygments==2.19.1 +pymeshlab==2023.12.post1 +pyngrok==7.2.3 +pyparsing==3.2.3 +pyquaternion==0.9.9 +PySocks==1.7.1 +python-box==6.1.0 +python-dateutil==2.9.0.post0 +python-engineio==4.11.2 +python-json-logger==3.3.0 +python-socketio==5.12.1 +pytorch-msssim==1.0.0 +pytz==2025.2 +pywin32==310 +pywinpty==2.0.15 +PyYAML==6.0.2 +pyzmq==26.4.0 +rawpy==0.24.0 +referencing==0.36.2 +regex==2024.11.6 +requests==2.32.3 +requests-toolbelt==1.0.0 +retrying==1.3.4 +rfc3339-validator==0.1.4 +rfc3986-validator==0.1.1 +rich==14.0.0 +rpds-py==0.24.0 +rtree==1.4.0 +scikit-image==0.25.2 +scikit-learn==1.6.1 +scipy==1.15.2 +semantic-version==2.10.0 +Send2Trash==1.8.3 +sentencepiece==0.1.99 +sentry-sdk==2.25.1 +setproctitle==1.3.5 +shapely==2.1.0 +shtab==1.7.1 +simple-websocket==1.1.0 +simplejson==3.20.1 +six==1.17.0 +smmap==5.0.2 +sniffio==1.3.1 +soupsieve==2.6 +splatfacto-w @ git+https://github.com/KevinXu02/splatfacto-w@119a3bfb3aa03669278e174ff11c4dfdcbcf97d7 +splines==0.3.0 +stack-data==0.6.3 +svg.path==6.3 +sympy==1.13.3 +tensorboard==2.19.0 +tensorboard-data-server==0.7.2 +tensorboardX==2.6.2.2 +tensorly==0.9.0 +termcolor==3.0.1 +terminado==0.18.1 +threadpoolctl==3.6.0 +tifffile==2025.3.30 +timm==0.6.7 +tinycss2==1.4.0 +tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@075158a70b87dba8729188a9cadc9411cfa4b71d#subdirectory=bindings/torch +tokenizers==0.13.3 +tomli==2.2.1 +pip install git+https://github.com/cvachha/instruct-gs2gs +torch==2.1.2+cu118 +torch-fidelity==0.3.0 +torch_scatter==2.1.2 +torchmetrics==1.7.1 +torchvision==0.16.2+cu118 +tornado==6.4.2 +tqdm==4.67.1 +traitlets==5.14.3 +transformers==4.29.2 +trimesh==4.6.6 +typeguard==4.4.2 +types-python-dateutil==2.9.0.20241206 +typing-inspection==0.4.0 +typing_extensions==4.13.2 +tyro==0.8.12 +tzdata==2025.2 +uri-template==1.3.0 +urllib3==2.4.0 +vhacdx==0.0.8.post2 +viser==0.2.7 +wadler_lindig==0.1.4 +wandb==0.19.9 +wcwidth==0.2.13 +webcolors==24.11.1 +webencodings==0.5.1 +websocket-client==1.8.0 +websockets==15.0.1 +Werkzeug==3.0.6 +widgetsnbextension==4.0.14 +wrapt==1.17.2 +wsproto==1.2.0 +wurlitzer==3.1.1 +xatlas==0.0.10 +xxhash==3.5.0 +yourdfpy==0.0.57 +-e git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git@e081caeb81473fac6f057ceb2e560207b4ba5112#egg=zipnerf +pip install torch-scatter -f https://data.pyg.org/whl/torch-2.1.2+${CUDA}.html +zipp==3.21.0 diff --git a/requirements_post_zipnerf.txt b/requirements_post_zipnerf.txt index 096495458c..05ae5e0508 100644 --- a/requirements_post_zipnerf.txt +++ b/requirements_post_zipnerf.txt @@ -212,6 +212,7 @@ tinycss2==1.4.0 tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@075158a70b87dba8729188a9cadc9411cfa4b71d#subdirectory=bindings/torch tokenizers==0.13.3 tomli==2.2.1 +pip install git+https://github.com/cvachha/instruct-gs2gs torch==2.1.2+cu118 torch-fidelity==0.3.0 torch_scatter==2.1.2 @@ -248,4 +249,5 @@ xatlas==0.0.10 xxhash==3.5.0 yourdfpy==0.0.57 -e git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git@e081caeb81473fac6f057ceb2e560207b4ba5112#egg=zipnerf +pip install torch-scatter -f https://data.pyg.org/whl/torch-2.1.2+${CUDA}.html zipp==3.21.0 diff --git a/test_cli.py b/test_cli.py new file mode 100644 index 0000000000..21f4d449c5 --- /dev/null +++ b/test_cli.py @@ -0,0 +1,86 @@ +import subprocess +import sys +import shutil + + +# Optional expected modules to validate trainer registration +EXPECTED_TRAINERS = [ + "zipnerf", + "splatfacto", + "sdfstudio", + "gs2gs", + "nerfgs" +] + +def run_command(cmd, description=""): + print(f"\n🔹 Running: {cmd}") + try: + result = subprocess.run(cmd, shell=True, capture_output=True, text=True) + if result.returncode != 0: + print(f"❌ Failed: {description or cmd}") + print(result.stderr) + return False + print("✅ Success") + return result.stdout + except Exception as e: + print(f"❌ Exception while running {cmd}:\n{e}") + return False + + +def command_exists(command): + return shutil.which(command) is not None + + +def main(): + print("🔧 Nerfstudio CLI Validation Tool\n") + + # 1. Check if CLI commands exist + for cmd in ["ns-train", "ns-viewer", "ns-process-data"]: + if not command_exists(cmd): + print(f"❌ Command not found: {cmd}. Is nerfstudio CLI installed?") + return + else: + print(f"✔️ Found CLI command: {cmd}") + + # 2. Check basic help commands + if not run_command("ns-train --help", "Check ns-train help"): return + if not run_command("ns-viewer --help", "Check ns-viewer help"): return + + # 3. Parse trainer list + print("\n📋 Checking registered trainers:") + output = run_command("ns-train --help", "List trainers") + if not output: return + + trainers = [] + for line in output.splitlines(): + if "usage: ns-train" in line.lower(): + continue + if "--" in line or "Options:" in line: + break + if line.strip(): + trainers.append(line.strip()) + + print(f"\n✅ Detected trainers:") + for t in trainers: + print(f" - {t}") + + # 4. Check for expected trainers (from add-ons) + print("\n🔍 Verifying addon trainer registration:") + missing = [] + for expected in EXPECTED_TRAINERS: + if not any(expected in t for t in trainers): + print(f"❗ Missing expected trainer: {expected}") + missing.append(expected) + else: + print(f"✔️ Found: {expected}") + + if missing: + print("\n⚠️ Some trainers appear to be missing. Did you run `ns-install-cli` after installing modules?") + else: + print("\n🎉 All expected addon trainers are registered.") + + print("\n✅ CLI Validation Complete.") + + +if __name__ == "__main__": + main() From 362247c7af953d53536e6634424ca90c26a5baff Mon Sep 17 00:00:00 2001 From: Francesco Christopher Date: Thu, 8 Jan 2026 22:00:52 +0100 Subject: [PATCH 3/8] cleanup --- test_cli.bat | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 test_cli.bat diff --git a/test_cli.bat b/test_cli.bat new file mode 100644 index 0000000000..a315890a05 --- /dev/null +++ b/test_cli.bat @@ -0,0 +1,34 @@ +@echo off +echo. +echo ========== Nerfstudio CLI Validator ========== +echo. + +REM Check if CLI works +echo Running: ns-train --help +ns-train --help +if errorlevel 1 ( + echo ❌ ERROR: ns-train failed to run. CLI may be broken or module not registered. + goto end +) + +REM Check if viewer works +echo. +echo Running: ns-viewer --help +ns-viewer --help +if errorlevel 1 ( + echo ❌ ERROR: ns-viewer failed to run. + goto end +) + +REM Optional: Detect available trainers +echo. +echo 🔍 Listing available trainers: +ns-train --help | findstr /R "Usage:.*" + +REM (Optional dry-run logic can be added here per addon) + +echo. +echo ✅ CLI appears to be working correctly. + +:end +pause \ No newline at end of file From ec93779ada399347f6105e36d5e61906ae38b6c5 Mon Sep 17 00:00:00 2001 From: Francesco Christopher Date: Thu, 8 Jan 2026 22:36:42 +0100 Subject: [PATCH 4/8] new basic + extra algorythms installation batches + cli validation test --- README_FULL.md | 3 +++ base.bat | 4 ++-- test_cli.bat | 6 +++++- test_cli.py | 20 ++++++++++++-------- 4 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 README_FULL.md diff --git a/README_FULL.md b/README_FULL.md new file mode 100644 index 0000000000..25a213d3f0 --- /dev/null +++ b/README_FULL.md @@ -0,0 +1,3 @@ +install nerfstudio via base.bat Conda or python venv(experimental) +install extra nerfstudio algorythms via extras.bat +validate the installed and available algorythms with test_cli.py diff --git a/base.bat b/base.bat index a0a3a2a6ad..a06a7e1930 100644 --- a/base.bat +++ b/base.bat @@ -3,8 +3,8 @@ setlocal enabledelayedexpansion REM ==== CONFIG ==== set ENV_NAME=nerfstudio -set YAML_FILE=nerfstudio_stable_environment_post_zipnerf.yaml -set REQUIREMENTS=requirements_post_zipnerf.txt +set YAML_FILE=requirements_conda.yaml +set REQUIREMENTS=requirements_pip.txt set PYTHON_EXE=python echo. diff --git a/test_cli.bat b/test_cli.bat index a315890a05..b04e03822b 100644 --- a/test_cli.bat +++ b/test_cli.bat @@ -2,6 +2,10 @@ echo. echo ========== Nerfstudio CLI Validator ========== echo. +@echo off +REM Ensure UTF-8 output +chcp 65001 > nul +set PYTHONIOENCODING=utf-8 REM Check if CLI works echo Running: ns-train --help @@ -31,4 +35,4 @@ echo. echo ✅ CLI appears to be working correctly. :end -pause \ No newline at end of file +pause diff --git a/test_cli.py b/test_cli.py index 21f4d449c5..8cd3ec2aea 100644 --- a/test_cli.py +++ b/test_cli.py @@ -1,7 +1,14 @@ +# test_cli.py import subprocess import sys import shutil +import io +import os +# Force UTF-8 encoding +sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding='utf-8') +sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding='utf-8') +os.environ["PYTHONIOENCODING"] = "utf-8" # Optional expected modules to validate trainer registration EXPECTED_TRAINERS = [ @@ -15,7 +22,7 @@ def run_command(cmd, description=""): print(f"\n🔹 Running: {cmd}") try: - result = subprocess.run(cmd, shell=True, capture_output=True, text=True) + result = subprocess.run(cmd, shell=True, capture_output=True, text=True, encoding='utf-8') if result.returncode != 0: print(f"❌ Failed: {description or cmd}") print(result.stderr) @@ -26,15 +33,13 @@ def run_command(cmd, description=""): print(f"❌ Exception while running {cmd}:\n{e}") return False - def command_exists(command): return shutil.which(command) is not None - def main(): print("🔧 Nerfstudio CLI Validation Tool\n") - # 1. Check if CLI commands exist + # 1. Check CLI tools for cmd in ["ns-train", "ns-viewer", "ns-process-data"]: if not command_exists(cmd): print(f"❌ Command not found: {cmd}. Is nerfstudio CLI installed?") @@ -42,11 +47,11 @@ def main(): else: print(f"✔️ Found CLI command: {cmd}") - # 2. Check basic help commands + # 2. CLI Help Check if not run_command("ns-train --help", "Check ns-train help"): return if not run_command("ns-viewer --help", "Check ns-viewer help"): return - # 3. Parse trainer list + # 3. Trainer Parsing print("\n📋 Checking registered trainers:") output = run_command("ns-train --help", "List trainers") if not output: return @@ -64,7 +69,7 @@ def main(): for t in trainers: print(f" - {t}") - # 4. Check for expected trainers (from add-ons) + # 4. Validate Addons print("\n🔍 Verifying addon trainer registration:") missing = [] for expected in EXPECTED_TRAINERS: @@ -81,6 +86,5 @@ def main(): print("\n✅ CLI Validation Complete.") - if __name__ == "__main__": main() From 3fbd218725922bb558d54d1c5e26df980e4d6d30 Mon Sep 17 00:00:00 2001 From: Francesco Christopher Date: Thu, 8 Jan 2026 23:00:01 +0100 Subject: [PATCH 5/8] new basic + extra algorythms installation batches + cli validation test --- .../process_data/colmap_utils - Copia.py | 714 ------------------ 1 file changed, 714 deletions(-) delete mode 100644 nerfstudio/process_data/colmap_utils - Copia.py diff --git a/nerfstudio/process_data/colmap_utils - Copia.py b/nerfstudio/process_data/colmap_utils - Copia.py deleted file mode 100644 index 1d9405c81a..0000000000 --- a/nerfstudio/process_data/colmap_utils - Copia.py +++ /dev/null @@ -1,714 +0,0 @@ -# Copyright 2022 the Regents of the University of California, Nerfstudio Team and contributors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Tools supporting the execution of COLMAP and preparation of COLMAP-based datasets for nerfstudio training. -""" - -import json -from pathlib import Path -from typing import Any, Dict, Literal, Optional, Union - -import appdirs -import cv2 -import numpy as np -import requests -import torch -from packaging.version import Version -from rich.progress import track - -# TODO(1480) use pycolmap instead of colmap_parsing_utils -# import pycolmap -from nerfstudio.data.utils.colmap_parsing_utils import ( - qvec2rotmat, - read_cameras_binary, - read_images_binary, - read_points3D_binary, - read_points3D_text, -) -from nerfstudio.process_data.process_data_utils import CameraModel -from nerfstudio.utils import colormaps -from nerfstudio.utils.rich_utils import CONSOLE, status -from nerfstudio.utils.scripts import run_command - - -def get_colmap_version(colmap_cmd: str, default_version: str = "3.8") -> Version: - """Returns the version of COLMAP. - This code assumes that colmap returns a version string of the form - "COLMAP 3.8 ..." which may not be true for all versions of COLMAP. - - Args: - default_version: Default version to return if COLMAP version can't be determined. - Returns: - The version of COLMAP. - """ - output = run_command(f"{colmap_cmd} -h", verbose=False) - assert output is not None - for line in output.split("\n"): - if line.startswith("COLMAP"): - version = line.split(" ")[1] - version = Version(version) - return version - CONSOLE.print(f"[bold red]Could not find COLMAP version. Using default {default_version}") - return Version(default_version) - - -def get_vocab_tree() -> Path: - """Return path to vocab tree. Downloads vocab tree if it doesn't exist. - - Returns: - The path to the vocab tree. - """ - vocab_tree_filename = Path(appdirs.user_data_dir("nerfstudio")) / "vocab_tree.fbow" - - if not vocab_tree_filename.exists(): - r = requests.get("https://demuc.de/colmap/vocab_tree_flickr100K_words32K.bin", stream=True) - vocab_tree_filename.parent.mkdir(parents=True, exist_ok=True) - with open(vocab_tree_filename, "wb") as f: - total_length = r.headers.get("content-length") - assert total_length is not None - for chunk in track( - r.iter_content(chunk_size=1024), - total=int(total_length) / 1024 + 1, - description="Downloading vocab tree...", - ): - if chunk: - f.write(chunk) - f.flush() - return vocab_tree_filename - - -def run_colmap( - image_dir: Path, - colmap_dir: Path, - camera_model: CameraModel, - camera_mask_path: Optional[Path] = None, - gpu: bool = True, - verbose: bool = False, - matching_method: Literal["vocab_tree", "exhaustive", "sequential"] = "vocab_tree", - refine_intrinsics: bool = True, - colmap_cmd: str = "colmap", -) -> None: - """Runs COLMAP on the images. - - Args: - image_dir: Path to the directory containing the images. - colmap_dir: Path to the output directory. - camera_model: Camera model to use. - camera_mask_path: Path to the camera mask. - gpu: If True, use GPU. - verbose: If True, logs the output of the command. - matching_method: Matching method to use. - refine_intrinsics: If True, refine intrinsics. - colmap_cmd: Path to the COLMAP executable. - """ - - colmap_version = get_colmap_version(colmap_cmd) - - colmap_database_path = colmap_dir / "database.db" - colmap_database_path.unlink(missing_ok=True) - - # Feature extraction - feature_extractor_cmd = [ - f"{colmap_cmd} feature_extractor", - f"--database_path {colmap_dir / 'database.db'}", - f"--image_path {image_dir}", - "--ImageReader.single_camera 1", - f"--ImageReader.camera_model {camera_model.value}", - f"--SiftExtraction.use_gpu {int(gpu)}", - ] - if camera_mask_path is not None: - feature_extractor_cmd.append(f"--ImageReader.camera_mask_path {camera_mask_path}") - feature_extractor_cmd = " ".join(feature_extractor_cmd) - with status(msg="[bold yellow]Running COLMAP feature extractor...", spinner="moon", verbose=verbose): - run_command(feature_extractor_cmd, verbose=verbose) - - CONSOLE.log("[bold green]:tada: Done extracting COLMAP features.") - - # Feature matching - feature_matcher_cmd = [ - f"{colmap_cmd} {matching_method}_matcher", - f"--database_path {colmap_dir / 'database.db'}", - f"--SiftMatching.use_gpu {int(gpu)}", - ] - if matching_method == "vocab_tree": - vocab_tree_filename = get_vocab_tree() - feature_matcher_cmd.append(f'--VocabTreeMatching.vocab_tree_path "{vocab_tree_filename}"') - feature_matcher_cmd = " ".join(feature_matcher_cmd) - with status(msg="[bold yellow]Running COLMAP feature matcher...", spinner="runner", verbose=verbose): - run_command(feature_matcher_cmd, verbose=verbose) - CONSOLE.log("[bold green]:tada: Done matching COLMAP features.") - - # Bundle adjustment - sparse_dir = colmap_dir / "sparse" - sparse_dir.mkdir(parents=True, exist_ok=True) - mapper_cmd = [ - f"{colmap_cmd} mapper", - f"--database_path {colmap_dir / 'database.db'}", - f"--image_path {image_dir}", - f"--output_path {sparse_dir}", - ] - if colmap_version >= Version("3.7"): - mapper_cmd.append("--Mapper.ba_global_function_tolerance=1e-6") - - mapper_cmd = " ".join(mapper_cmd) - - with status( - msg="[bold yellow]Running COLMAP bundle adjustment... (This may take a while)", - spinner="circle", - verbose=verbose, - ): - run_command(mapper_cmd, verbose=verbose) - CONSOLE.log("[bold green]:tada: Done COLMAP bundle adjustment.") - - if refine_intrinsics: - with status(msg="[bold yellow]Refine intrinsics...", spinner="dqpb", verbose=verbose): - bundle_adjuster_cmd = [ - f"{colmap_cmd} bundle_adjuster", - f"--input_path {sparse_dir}/0", - f"--output_path {sparse_dir}/0", - "--BundleAdjustment.refine_principal_point 1", - ] - run_command(" ".join(bundle_adjuster_cmd), verbose=verbose) - CONSOLE.log("[bold green]:tada: Done refining intrinsics.") - - -def parse_colmap_camera_params(camera) -> Dict[str, Any]: - """ - Parses all currently supported COLMAP cameras into the transforms.json metadata - - Args: - camera: COLMAP camera - Returns: - transforms.json metadata containing camera's intrinsics and distortion parameters - - """ - out: Dict[str, Any] = { - "w": camera.width, - "h": camera.height, - } - - # Parameters match https://github.com/colmap/colmap/blob/dev/src/base/camera_models.h - camera_params = camera.params - if camera.model == "SIMPLE_PINHOLE": - # du = 0 - # dv = 0 - out["fl_x"] = float(camera_params[0]) - out["fl_y"] = float(camera_params[0]) - out["cx"] = float(camera_params[1]) - out["cy"] = float(camera_params[2]) - out["k1"] = 0.0 - out["k2"] = 0.0 - out["p1"] = 0.0 - out["p2"] = 0.0 - camera_model = CameraModel.OPENCV - elif camera.model == "PINHOLE": - # f, cx, cy, k - - # du = 0 - # dv = 0 - out["fl_x"] = float(camera_params[0]) - out["fl_y"] = float(camera_params[1]) - out["cx"] = float(camera_params[2]) - out["cy"] = float(camera_params[3]) - out["k1"] = 0.0 - out["k2"] = 0.0 - out["p1"] = 0.0 - out["p2"] = 0.0 - camera_model = CameraModel.OPENCV - elif camera.model == "SIMPLE_RADIAL": - # f, cx, cy, k - - # r2 = u**2 + v**2; - # radial = k * r2 - # du = u * radial - # dv = u * radial - out["fl_x"] = float(camera_params[0]) - out["fl_y"] = float(camera_params[0]) - out["cx"] = float(camera_params[1]) - out["cy"] = float(camera_params[2]) - out["k1"] = float(camera_params[3]) - out["k2"] = 0.0 - out["p1"] = 0.0 - out["p2"] = 0.0 - camera_model = CameraModel.OPENCV - elif camera.model == "RADIAL": - # f, cx, cy, k1, k2 - - # r2 = u**2 + v**2; - # radial = k1 * r2 + k2 * r2 ** 2 - # du = u * radial - # dv = v * radial - out["fl_x"] = float(camera_params[0]) - out["fl_y"] = float(camera_params[0]) - out["cx"] = float(camera_params[1]) - out["cy"] = float(camera_params[2]) - out["k1"] = float(camera_params[3]) - out["k2"] = float(camera_params[4]) - out["p1"] = 0.0 - out["p2"] = 0.0 - camera_model = CameraModel.OPENCV - elif camera.model == "OPENCV": - # fx, fy, cx, cy, k1, k2, p1, p2 - - # uv = u * v; - # r2 = u**2 + v**2 - # radial = k1 * r2 + k2 * r2 ** 2 - # du = u * radial + 2 * p1 * u*v + p2 * (r2 + 2 * u**2) - # dv = v * radial + 2 * p2 * u*v + p1 * (r2 + 2 * v**2) - out["fl_x"] = float(camera_params[0]) - out["fl_y"] = float(camera_params[1]) - out["cx"] = float(camera_params[2]) - out["cy"] = float(camera_params[3]) - out["k1"] = float(camera_params[4]) - out["k2"] = float(camera_params[5]) - out["p1"] = float(camera_params[6]) - out["p2"] = float(camera_params[7]) - camera_model = CameraModel.OPENCV - elif camera.model == "OPENCV_FISHEYE": - # fx, fy, cx, cy, k1, k2, k3, k4 - - # r = sqrt(u**2 + v**2) - - # if r > eps: - # theta = atan(r) - # theta2 = theta ** 2 - # theta4 = theta2 ** 2 - # theta6 = theta4 * theta2 - # theta8 = theta4 ** 2 - # thetad = theta * (1 + k1 * theta2 + k2 * theta4 + k3 * theta6 + k4 * theta8) - # du = u * thetad / r - u; - # dv = v * thetad / r - v; - # else: - # du = dv = 0 - out["fl_x"] = float(camera_params[0]) - out["fl_y"] = float(camera_params[1]) - out["cx"] = float(camera_params[2]) - out["cy"] = float(camera_params[3]) - out["k1"] = float(camera_params[4]) - out["k2"] = float(camera_params[5]) - out["k3"] = float(camera_params[6]) - out["k4"] = float(camera_params[7]) - camera_model = CameraModel.OPENCV_FISHEYE - elif camera.model == "FULL_OPENCV": - # fx, fy, cx, cy, k1, k2, p1, p2, k3, k4, k5, k6 - - # u2 = u ** 2 - # uv = u * v - # v2 = v ** 2 - # r2 = u2 + v2 - # r4 = r2 * r2 - # r6 = r4 * r2 - # radial = (1 + k1 * r2 + k2 * r4 + k3 * r6) / - # (1 + k4 * r2 + k5 * r4 + k6 * r6) - # du = u * radial + 2 * p1 * uv + p2 * (r2 + 2 * u2) - u - # dv = v * radial + 2 * p2 * uv + p1 * (r2 + 2 * v2) - v - out["fl_x"] = float(camera_params[0]) - out["fl_y"] = float(camera_params[1]) - out["cx"] = float(camera_params[2]) - out["cy"] = float(camera_params[3]) - out["k1"] = float(camera_params[4]) - out["k2"] = float(camera_params[5]) - out["p1"] = float(camera_params[6]) - out["p2"] = float(camera_params[7]) - out["k3"] = float(camera_params[8]) - out["k4"] = float(camera_params[9]) - out["k5"] = float(camera_params[10]) - out["k6"] = float(camera_params[11]) - raise NotImplementedError(f"{camera.model} camera model is not supported yet!") - elif camera.model == "FOV": - # fx, fy, cx, cy, omega - out["fl_x"] = float(camera_params[0]) - out["fl_y"] = float(camera_params[1]) - out["cx"] = float(camera_params[2]) - out["cy"] = float(camera_params[3]) - out["omega"] = float(camera_params[4]) - raise NotImplementedError(f"{camera.model} camera model is not supported yet!") - elif camera.model == "SIMPLE_RADIAL_FISHEYE": - # f, cx, cy, k - - # r = sqrt(u ** 2 + v ** 2) - # if r > eps: - # theta = atan(r) - # theta2 = theta ** 2 - # thetad = theta * (1 + k * theta2) - # du = u * thetad / r - u; - # dv = v * thetad / r - v; - # else: - # du = dv = 0 - out["fl_x"] = float(camera_params[0]) - out["fl_y"] = float(camera_params[0]) - out["cx"] = float(camera_params[1]) - out["cy"] = float(camera_params[2]) - out["k1"] = float(camera_params[3]) - out["k2"] = 0.0 - out["k3"] = 0.0 - out["k4"] = 0.0 - camera_model = CameraModel.OPENCV_FISHEYE - elif camera.model == "RADIAL_FISHEYE": - # f, cx, cy, k1, k2 - - # r = sqrt(u ** 2 + v ** 2) - # if r > eps: - # theta = atan(r) - # theta2 = theta ** 2 - # theta4 = theta2 ** 2 - # thetad = theta * (1 + k * theta2) - # thetad = theta * (1 + k1 * theta2 + k2 * theta4) - # du = u * thetad / r - u; - # dv = v * thetad / r - v; - # else: - # du = dv = 0 - out["fl_x"] = float(camera_params[0]) - out["fl_y"] = float(camera_params[0]) - out["cx"] = float(camera_params[1]) - out["cy"] = float(camera_params[2]) - out["k1"] = float(camera_params[3]) - out["k2"] = float(camera_params[4]) - out["k3"] = 0 - out["k4"] = 0 - camera_model = CameraModel.OPENCV_FISHEYE - else: - # THIN_PRISM_FISHEYE not supported! - raise NotImplementedError(f"{camera.model} camera model is not supported yet!") - - out["camera_model"] = camera_model.value - return out - - -def colmap_to_json( - recon_dir: Path, - output_dir: Path, - camera_mask_path: Optional[Path] = None, - image_id_to_depth_path: Optional[Dict[int, Path]] = None, - image_rename_map: Optional[Dict[str, str]] = None, - ply_filename="sparse_pc.ply", - keep_original_world_coordinate: bool = False, - use_single_camera_mode: bool = True, -) -> int: - """Converts COLMAP's cameras.bin and images.bin to a JSON file. - - Args: - recon_dir: Path to the reconstruction directory, e.g. "sparse/0" - output_dir: Path to the output directory. - camera_model: Camera model used. - camera_mask_path: Path to the camera mask. - image_id_to_depth_path: When including sfm-based depth, embed these depth file paths in the exported json - image_rename_map: Use these image names instead of the names embedded in the COLMAP db - keep_original_world_coordinate: If True, no extra transform will be applied to world coordinate. - Colmap optimized world often have y direction of the first camera pointing towards down direction, - while nerfstudio world set z direction to be up direction for viewer. - Returns: - The number of registered images. - """ - - # TODO(1480) use pycolmap - # recon = pycolmap.Reconstruction(recon_dir) - # cam_id_to_camera = recon.cameras - # im_id_to_image = recon.images - cam_id_to_camera = read_cameras_binary(recon_dir / "cameras.bin") - im_id_to_image = read_images_binary(recon_dir / "images.bin") - if set(cam_id_to_camera.keys()) != {1}: - CONSOLE.print(f"[bold yellow]Warning: More than one camera is found in {recon_dir}") - print(cam_id_to_camera) - use_single_camera_mode = False # update bool: one camera per frame - out = {} # out = {"camera_model": parse_colmap_camera_params(cam_id_to_camera[1])["camera_model"]} - else: # one camera for all frames - out = parse_colmap_camera_params(cam_id_to_camera[1]) - - frames = [] - for im_id, im_data in im_id_to_image.items(): - # NB: COLMAP uses Eigen / scalar-first quaternions - # * https://colmap.github.io/format.html - # * https://github.com/colmap/colmap/blob/bf3e19140f491c3042bfd85b7192ef7d249808ec/src/base/pose.cc#L75 - # the `rotation_matrix()` handles that format for us. - - # TODO(1480) BEGIN use pycolmap API - # rotation = im_data.rotation_matrix() - rotation = qvec2rotmat(im_data.qvec) - - translation = im_data.tvec.reshape(3, 1) - w2c = np.concatenate([rotation, translation], 1) - w2c = np.concatenate([w2c, np.array([[0, 0, 0, 1]])], 0) - c2w = np.linalg.inv(w2c) - # Convert from COLMAP's camera coordinate system (OpenCV) to ours (OpenGL) - c2w[0:3, 1:3] *= -1 - if not keep_original_world_coordinate: - c2w = c2w[np.array([0, 2, 1, 3]), :] - c2w[2, :] *= -1 - - name = im_data.name - if image_rename_map is not None: - name = image_rename_map[name] - name = Path(f"./images/{name}") - - frame = { - "file_path": name.as_posix(), - "transform_matrix": c2w.tolist(), - "colmap_im_id": im_id, - } - if camera_mask_path is not None: - frame["mask_path"] = camera_mask_path.relative_to(camera_mask_path.parent.parent).as_posix() - if image_id_to_depth_path is not None: - depth_path = image_id_to_depth_path[im_id] - frame["depth_file_path"] = str(depth_path.relative_to(depth_path.parent.parent)) - - if not use_single_camera_mode: # add the camera parameters for this frame - frame.update(parse_colmap_camera_params(cam_id_to_camera[im_data.camera_id])) - - frames.append(frame) - - out["frames"] = frames - - applied_transform = None - if not keep_original_world_coordinate: - applied_transform = np.eye(4)[:3, :] - applied_transform = applied_transform[np.array([0, 2, 1]), :] - applied_transform[2, :] *= -1 - out["applied_transform"] = applied_transform.tolist() - - # create ply from colmap - assert ply_filename.endswith(".ply"), f"ply_filename: {ply_filename} does not end with '.ply'" - create_ply_from_colmap( - ply_filename, - recon_dir, - output_dir, - torch.from_numpy(applied_transform).float() if applied_transform is not None else None, - ) - out["ply_file_path"] = ply_filename - - with open(output_dir / "transforms.json", "w", encoding="utf-8") as f: - json.dump(out, f, indent=4) - - return len(frames) - - -def create_sfm_depth( - recon_dir: Path, - output_dir: Path, - verbose: bool = True, - depth_scale_to_integer_factor: float = 1000.0, - min_depth: float = 0.001, - max_depth: float = 10000, - max_repoj_err: float = 2.5, - min_n_visible: int = 2, - include_depth_debug: bool = False, - input_images_dir: Optional[Path] = None, -) -> Dict[int, Path]: - """Converts COLMAP's points3d.bin to sparse depth map images encoded as - 16-bit "millimeter depth" PNGs. - - Notes: - * This facility does NOT use COLMAP dense reconstruction; it creates depth - maps from sparse SfM points here. - * COLMAP does *not* reconstruct metric depth unless you give it calibrated - (metric) intrinsics as input. Therefore, "depth" in this function has - potentially ambiguous units. - - Args: - recon_dir: Path to the reconstruction directory, e.g. "sparse/0" - output_dir: Path to the output directory. - verbose: If True, logs progress of depth image creation. - depth_scale_to_integer_factor: Use this parameter to tune the conversion of - raw depth measurements to integer depth values. This value should - be equal to 1. / `depth_unit_scale_factor`, where - `depth_unit_scale_factor` is the value you provide at training time. - E.g. for millimeter depth, leave `depth_unit_scale_factor` at 1e-3 - and depth_scale_to_integer_factor at 1000. - min_depth: Discard points closer than this to the camera. - max_depth: Discard points farther than this from the camera. - max_repoj_err: Discard points with reprojection error greater than this - amount (in pixels). - min_n_visible: Discard 3D points that have been triangulated with fewer - than this many frames. - include_depth_debug: Also include debug images showing depth overlaid - upon RGB. - Returns: - Depth file paths indexed by COLMAP image id - """ - - # TODO(1480) use pycolmap - # recon = pycolmap.Reconstruction(recon_dir) - # ptid_to_info = recon.points3D - # cam_id_to_camera = recon.cameras - # im_id_to_image = recon.images - ptid_to_info = read_points3D_binary(recon_dir / "points3D.bin") - cam_id_to_camera = read_cameras_binary(recon_dir / "cameras.bin") - im_id_to_image = read_images_binary(recon_dir / "images.bin") - - # Only support first camera - CAMERA_ID = 1 - W = cam_id_to_camera[CAMERA_ID].width - H = cam_id_to_camera[CAMERA_ID].height - - if verbose: - iter_images = track( - im_id_to_image.items(), total=len(im_id_to_image.items()), description="Creating depth maps ..." - ) - else: - iter_images = iter(im_id_to_image.items()) - - image_id_to_depth_path = {} - for im_id, im_data in iter_images: - # TODO(1480) BEGIN delete when abandoning colmap_parsing_utils - pids = [pid for pid in im_data.point3D_ids if pid != -1] - xyz_world = np.array([ptid_to_info[pid].xyz for pid in pids]) - rotation = qvec2rotmat(im_data.qvec) - z = (rotation @ xyz_world.T)[-1] + im_data.tvec[-1] - errors = np.array([ptid_to_info[pid].error for pid in pids]) - n_visible = np.array([len(ptid_to_info[pid].image_ids) for pid in pids]) - uv = np.array([im_data.xys[i] for i in range(len(im_data.xys)) if im_data.point3D_ids[i] != -1]) - # TODO(1480) END delete when abandoning colmap_parsing_utils - - # TODO(1480) BEGIN use pycolmap API - - # # Get only keypoints that have corresponding triangulated 3D points - # p2ds = im_data.get_valid_points2D() - - # xyz_world = np.array([ptid_to_info[p2d.point3D_id].xyz for p2d in p2ds]) - - # # COLMAP OpenCV convention: z is always positive - # z = (im_data.rotation_matrix() @ xyz_world.T)[-1] + im_data.tvec[-1] - - # # Mean reprojection error in image space - # errors = np.array([ptid_to_info[p2d.point3D_id].error for p2d in p2ds]) - - # # Number of frames in which each frame is visible - # n_visible = np.array([ptid_to_info[p2d.point3D_id].track.length() for p2d in p2ds]) - - # Note: these are *unrectified* pixel coordinates that should match the original input - # no matter the camera model - # uv = np.array([p2d.xy for p2d in p2ds]) - - # TODO(1480) END use pycolmap API - - idx = np.where( - (z >= min_depth) - & (z <= max_depth) - & (errors <= max_repoj_err) - & (n_visible >= min_n_visible) - & (uv[:, 0] >= 0) - & (uv[:, 0] < W) - & (uv[:, 1] >= 0) - & (uv[:, 1] < H) - ) - z = z[idx] - uv = uv[idx] - - uu, vv = uv[:, 0].astype(int), uv[:, 1].astype(int) - depth = np.zeros((H, W), dtype=np.float32) - depth[vv, uu] = z - - # E.g. if `depth` is metric and in units of meters, and `depth_scale_to_integer_factor` - # is 1000, then `depth_img` will be integer millimeters. - depth_img = (depth_scale_to_integer_factor * depth).astype(np.uint16) - - out_name = str(im_data.name) - depth_path = output_dir / out_name - if depth_path.suffix == ".jpg": - depth_path = depth_path.with_suffix(".png") - cv2.imwrite(str(depth_path), depth_img) # type: ignore - - image_id_to_depth_path[im_id] = depth_path - - if include_depth_debug: - assert input_images_dir is not None, "Need explicit input_images_dir for debug images" - assert input_images_dir.exists(), input_images_dir - - depth_flat = depth.flatten()[:, None] - overlay = 255.0 * colormaps.apply_depth_colormap(torch.from_numpy(depth_flat)).numpy() - overlay = overlay.reshape([H, W, 3]) - input_image_path = input_images_dir / im_data.name - input_image = cv2.imread(str(input_image_path)) # type: ignore - debug = 0.3 * input_image + 0.7 + overlay - - out_name = out_name + ".debug.jpg" - output_path = output_dir / "debug_depth" / out_name - output_path.parent.mkdir(parents=True, exist_ok=True) - cv2.imwrite(str(output_path), debug.astype(np.uint8)) # type: ignore - - return image_id_to_depth_path - - -def get_matching_summary(num_initial_frames: int, num_matched_frames: int) -> str: - """Returns a summary of the matching results. - - Args: - num_initial_frames: The number of initial frames. - num_matched_frames: The number of matched frames. - - Returns: - A summary of the matching results. - """ - match_ratio = num_matched_frames / num_initial_frames - if match_ratio == 1: - return "[bold green]COLMAP found poses for all images, CONGRATS!" - if match_ratio < 0.4: - result = f"[bold red]COLMAP only found poses for {num_matched_frames / num_initial_frames * 100:.2f}%" - result += " of the images. This is low.\nThis can be caused by a variety of reasons," - result += " such poor scene coverage, blurry images, or large exposure changes." - return result - if match_ratio < 0.8: - result = f"[bold yellow]COLMAP only found poses for {num_matched_frames / num_initial_frames * 100:.2f}%" - result += " of the images.\nThis isn't great, but may be ok." - result += "\nMissing poses can be caused by a variety of reasons, such poor scene coverage, blurry images," - result += " or large exposure changes." - return result - return f"[bold green]COLMAP found poses for {num_matched_frames / num_initial_frames * 100:.2f}% of the images." - - -def create_ply_from_colmap( - filename: str, recon_dir: Path, output_dir: Path, applied_transform: Union[torch.Tensor, None] -) -> None: - """Writes a ply file from colmap. - - Args: - filename: file name for .ply - recon_dir: Directory to grab colmap points - output_dir: Directory to output .ply - """ - if (recon_dir / "points3D.bin").exists(): - colmap_points = read_points3D_binary(recon_dir / "points3D.bin") - elif (recon_dir / "points3D.txt").exists(): - colmap_points = read_points3D_text(recon_dir / "points3D.txt") - else: - raise ValueError(f"Could not find points3D.txt or points3D.bin in {recon_dir}") - - # Load point Positions - points3D = torch.from_numpy(np.array([p.xyz for p in colmap_points.values()], dtype=np.float32)) - if applied_transform is not None: - assert applied_transform.shape == (3, 4) - points3D = torch.einsum("ij,bj->bi", applied_transform[:3, :3], points3D) + applied_transform[:3, 3] - - # Load point colours - points3D_rgb = torch.from_numpy(np.array([p.rgb for p in colmap_points.values()], dtype=np.uint8)) - - # write ply - with open(output_dir / filename, "w") as f: - # Header - f.write("ply\n") - f.write("format ascii 1.0\n") - f.write(f"element vertex {len(points3D)}\n") - f.write("property float x\n") - f.write("property float y\n") - f.write("property float z\n") - f.write("property uint8 red\n") - f.write("property uint8 green\n") - f.write("property uint8 blue\n") - f.write("end_header\n") - - for coord, color in zip(points3D, points3D_rgb): - x, y, z = coord - r, g, b = color - f.write(f"{x:8f} {y:8f} {z:8f} {r} {g} {b}\n") From 079806f91d632cb5591ef649a68d34a10d058a4d Mon Sep 17 00:00:00 2001 From: Francesco Christopher Date: Thu, 8 Jan 2026 23:12:28 +0100 Subject: [PATCH 6/8] new basic + extra algorythms installation batches + cli validation test --- nerfstudio/scripts/exporter_frank.py | 676 --------------------------- 1 file changed, 676 deletions(-) delete mode 100644 nerfstudio/scripts/exporter_frank.py diff --git a/nerfstudio/scripts/exporter_frank.py b/nerfstudio/scripts/exporter_frank.py deleted file mode 100644 index 7d7d54be40..0000000000 --- a/nerfstudio/scripts/exporter_frank.py +++ /dev/null @@ -1,676 +0,0 @@ -# Copyright 2022 the Regents of the University of California, Nerfstudio Team and contributors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -""" -Script for exporting NeRF into other formats. -""" - -from __future__ import annotations - -import json -import os -import sys -import typing -from collections import OrderedDict -from dataclasses import dataclass, field -from importlib.metadata import version -from pathlib import Path -from typing import List, Optional, Tuple, Union, cast - -import numpy as np -import open3d as o3d -import torch -import tyro -from typing_extensions import Annotated, Literal - -from nerfstudio.cameras.rays import RayBundle -from nerfstudio.data.datamanagers.full_images_datamanager import FullImageDatamanager -from nerfstudio.data.datamanagers.random_cameras_datamanager import RandomCamerasDataManager -from nerfstudio.data.datamanagers.base_datamanager import VanillaDataManager -from nerfstudio.data.datamanagers.parallel_datamanager import ParallelDataManager -from nerfstudio.data.scene_box import OrientedBox -from nerfstudio.exporter import texture_utils, tsdf_utils -from nerfstudio.exporter.exporter_utils import collect_camera_poses, generate_point_cloud, get_mesh_from_filename -from nerfstudio.exporter.marching_cubes import generate_mesh_with_multires_marching_cubes -from nerfstudio.fields.sdf_field import SDFField # noqa -from nerfstudio.models.splatfacto import SplatfactoModel -from nerfstudio.pipelines.base_pipeline import Pipeline, VanillaPipeline -from nerfstudio.utils.eval_utils import eval_setup -from nerfstudio.utils.rich_utils import CONSOLE - - -@dataclass -class Exporter: - """Export the mesh from a YML config to a folder.""" - - load_config: Path - """Path to the config YAML file.""" - output_dir: Path - """Path to the output directory.""" - - -def validate_pipeline(normal_method: str, normal_output_name: str, pipeline: Pipeline) -> None: - """Check that the pipeline is valid for this exporter. - - Args: - normal_method: Method to estimate normals with. Either "open3d" or "model_output". - normal_output_name: Name of the normal output. - pipeline: Pipeline to evaluate with. - """ - if normal_method == "model_output": - CONSOLE.print("Checking that the pipeline has a normal output.") - origins = torch.zeros((1, 3), device=pipeline.device) - directions = torch.ones_like(origins) - pixel_area = torch.ones_like(origins[..., :1]) - camera_indices = torch.zeros_like(origins[..., :1]) - metadata = {"directions_norm": torch.linalg.vector_norm(directions, dim=-1, keepdim=True)} - ray_bundle = RayBundle( - origins=origins, - directions=directions, - pixel_area=pixel_area, - camera_indices=camera_indices, - metadata=metadata, - ) - outputs = pipeline.model(ray_bundle) - if normal_output_name not in outputs: - CONSOLE.print(f"[bold yellow]Warning: Normal output '{normal_output_name}' not found in pipeline outputs.") - CONSOLE.print(f"Available outputs: {list(outputs.keys())}") - CONSOLE.print( - "[bold yellow]Warning: Please train a model with normals " - "(e.g., nerfacto with predicted normals turned on)." - ) - CONSOLE.print("[bold yellow]Warning: Or change --normal-method") - CONSOLE.print("[bold yellow]Exiting early.") - sys.exit(1) - - -@dataclass -class ExportPointCloud(Exporter): - """Export NeRF as a point cloud.""" - - num_points: int = 1000000 - """Number of points to generate. May result in less if outlier removal is used.""" - remove_outliers: bool = True - """Remove outliers from the point cloud.""" - reorient_normals: bool = True - """Reorient point cloud normals based on view direction.""" - normal_method: Literal["open3d", "model_output"] = "model_output" - """Method to estimate normals with.""" - normal_output_name: str = "normals" - """Name of the normal output.""" - depth_output_name: str = "depth" - """Name of the depth output.""" - rgb_output_name: str = "rgb" - """Name of the RGB output.""" - - obb_center: Optional[Tuple[float, float, float]] = None - """Center of the oriented bounding box.""" - obb_rotation: Optional[Tuple[float, float, float]] = None - """Rotation of the oriented bounding box. Expressed as RPY Euler angles in radians""" - obb_scale: Optional[Tuple[float, float, float]] = None - """Scale of the oriented bounding box along each axis.""" - num_rays_per_batch: int = 32768 - """Number of rays to evaluate per batch. Decrease if you run out of memory.""" - std_ratio: float = 10.0 - """Threshold based on STD of the average distances across the point cloud to remove outliers.""" - save_world_frame: bool = False - """If set, saves the point cloud in the same frame as the original dataset. Otherwise, uses the - scaled and reoriented coordinate space expected by the NeRF models.""" - - def main(self) -> None: - """Export point cloud.""" - - if not self.output_dir.exists(): - self.output_dir.mkdir(parents=True) - - _, pipeline, _, _ = eval_setup(self.load_config) - - validate_pipeline(self.normal_method, self.normal_output_name, pipeline) - - # Increase the batchsize to speed up the evaluation. - assert isinstance( - pipeline.datamanager, - (VanillaDataManager, ParallelDataManager,FullImageDatamanager, RandomCamerasDataManager)) - if isinstance(pipeline.datamanager, VanillaDataManager): - assert pipeline.datamanager.train_pixel_sampler is not None - pipeline.datamanager.train_pixel_sampler.num_rays_per_batch = self.num_rays_per_batch - - # Whether the normals should be estimated based on the point cloud. - estimate_normals = self.normal_method == "open3d" - crop_obb = None - if self.obb_center is not None and self.obb_rotation is not None and self.obb_scale is not None: - crop_obb = OrientedBox.from_params(self.obb_center, self.obb_rotation, self.obb_scale) - pcd = generate_point_cloud( - pipeline=pipeline, - num_points=self.num_points, - remove_outliers=self.remove_outliers, - reorient_normals=self.reorient_normals, - estimate_normals=estimate_normals, - rgb_output_name=self.rgb_output_name, - depth_output_name=self.depth_output_name, - normal_output_name=self.normal_output_name if self.normal_method == "model_output" else None, - crop_obb=crop_obb, - std_ratio=self.std_ratio, - ) - if self.save_world_frame: - # apply the inverse dataparser transform to the point cloud - points = np.asarray(pcd.points) - poses = np.eye(4, dtype=np.float32)[None, ...].repeat(points.shape[0], axis=0)[:, :3, :] - poses[:, :3, 3] = points - poses = pipeline.datamanager.train_dataparser_outputs.transform_poses_to_original_space( - torch.from_numpy(poses) - ) - points = poses[:, :3, 3].numpy() - pcd.points = o3d.utility.Vector3dVector(points) - - torch.cuda.empty_cache() - - CONSOLE.print(f"[bold green]:white_check_mark: Generated {pcd}") - CONSOLE.print("Saving Point Cloud...") - tpcd = o3d.t.geometry.PointCloud.from_legacy(pcd) - # The legacy PLY writer converts colors to UInt8, - # let us do the same to save space. - tpcd.point.colors = (tpcd.point.colors * 255).to(o3d.core.Dtype.UInt8) # type: ignore - o3d.t.io.write_point_cloud(str(self.output_dir / "point_cloud.ply"), tpcd) - print("\033[A\033[A") - CONSOLE.print("[bold green]:white_check_mark: Saving Point Cloud") - - -@dataclass -class ExportTSDFMesh(Exporter): - """ - Export a mesh using TSDF processing. - """ - - downscale_factor: int = 2 - """Downscale the images starting from the resolution used for training.""" - depth_output_name: str = "depth" - """Name of the depth output.""" - rgb_output_name: str = "rgb" - """Name of the RGB output.""" - resolution: Union[int, List[int]] = field(default_factory=lambda: [128, 128, 128]) - """Resolution of the TSDF volume or [x, y, z] resolutions individually.""" - batch_size: int = 10 - """How many depth images to integrate per batch.""" - use_bounding_box: bool = True - """Whether to use a bounding box for the TSDF volume.""" - bounding_box_min: Tuple[float, float, float] = (-1, -1, -1) - """Minimum of the bounding box, used if use_bounding_box is True.""" - bounding_box_max: Tuple[float, float, float] = (1, 1, 1) - """Minimum of the bounding box, used if use_bounding_box is True.""" - texture_method: Literal["tsdf", "nerf"] = "nerf" - """Method to texture the mesh with. Either 'tsdf' or 'nerf'.""" - px_per_uv_triangle: int = 4 - """Number of pixels per UV triangle.""" - unwrap_method: Literal["xatlas", "custom"] = "xatlas" - """The method to use for unwrapping the mesh.""" - num_pixels_per_side: int = 2048 - """If using xatlas for unwrapping, the pixels per side of the texture image.""" - target_num_faces: Optional[int] = 50000 - """Target number of faces for the mesh to texture.""" - refine_mesh_using_initial_aabb_estimate: bool = False - """Refine the mesh using the initial AABB estimate.""" - refinement_epsilon: float = 1e-2 - """Refinement epsilon for the mesh. This is the distance in meters that the refined AABB/OBB will be expanded by - in each direction.""" - - def main(self) -> None: - """Export mesh""" - - if not self.output_dir.exists(): - self.output_dir.mkdir(parents=True) - - _, pipeline, _, _ = eval_setup(self.load_config) - - tsdf_utils.export_tsdf_mesh( - pipeline, - self.output_dir, - self.downscale_factor, - self.depth_output_name, - self.rgb_output_name, - self.resolution, - self.batch_size, - use_bounding_box=self.use_bounding_box, - bounding_box_min=self.bounding_box_min, - bounding_box_max=self.bounding_box_max, - refine_mesh_using_initial_aabb_estimate=self.refine_mesh_using_initial_aabb_estimate, - refinement_epsilon=self.refinement_epsilon, - ) - - # possibly - # texture the mesh with NeRF and export to a mesh.obj file - # and a material and texture file - if self.texture_method == "nerf": - # load the mesh from the tsdf export - mesh = get_mesh_from_filename( - str(self.output_dir / "tsdf_mesh.ply"), target_num_faces=self.target_num_faces - ) - CONSOLE.print("Texturing mesh with NeRF") - texture_utils.export_textured_mesh( - mesh, - pipeline, - self.output_dir, - px_per_uv_triangle=self.px_per_uv_triangle if self.unwrap_method == "custom" else None, - unwrap_method=self.unwrap_method, - num_pixels_per_side=self.num_pixels_per_side, - ) - - -@dataclass -class ExportPoissonMesh(Exporter): - """ - Export a mesh using poisson surface reconstruction. - """ - - num_points: int = 1000000 - """Number of points to generate. May result in less if outlier removal is used.""" - remove_outliers: bool = True - """Remove outliers from the point cloud.""" - reorient_normals: bool = True - """Reorient point cloud normals based on view direction.""" - depth_output_name: str = "depth" - """Name of the depth output.""" - rgb_output_name: str = "rgb" - """Name of the RGB output.""" - normal_method: Literal["open3d", "model_output"] = "model_output" - """Method to estimate normals with.""" - normal_output_name: str = "normals" - """Name of the normal output.""" - save_point_cloud: bool = False - """Whether to save the point cloud.""" - obb_center: Optional[Tuple[float, float, float]] = None - """Center of the oriented bounding box.""" - obb_rotation: Optional[Tuple[float, float, float]] = None - """Rotation of the oriented bounding box. Expressed as RPY Euler angles in radians""" - obb_scale: Optional[Tuple[float, float, float]] = None - """Scale of the oriented bounding box along each axis.""" - num_rays_per_batch: int = 32768 - """Number of rays to evaluate per batch. Decrease if you run out of memory.""" - texture_method: Literal["point_cloud", "nerf"] = "nerf" - """Method to texture the mesh with. Either 'point_cloud' or 'nerf'.""" - px_per_uv_triangle: int = 4 - """Number of pixels per UV triangle.""" - unwrap_method: Literal["xatlas", "custom"] = "xatlas" - """The method to use for unwrapping the mesh.""" - num_pixels_per_side: int = 2048 - """If using xatlas for unwrapping, the pixels per side of the texture image.""" - target_num_faces: Optional[int] = 50000 - """Target number of faces for the mesh to texture.""" - std_ratio: float = 10.0 - """Threshold based on STD of the average distances across the point cloud to remove outliers.""" - - def main(self) -> None: - """Export mesh""" - - if not self.output_dir.exists(): - self.output_dir.mkdir(parents=True) - - _, pipeline, _, _ = eval_setup(self.load_config) - - validate_pipeline(self.normal_method, self.normal_output_name, pipeline) - - # Increase the batchsize to speed up the evaluation. - assert isinstance( - pipeline.datamanager, - (VanillaDataManager, ParallelDataManager,FullImageDatamanager,RandomCamerasDataManager)) - if isinstance(pipeline.datamanager, VanillaDataManager): - assert pipeline.datamanager.train_pixel_sampler is not None - pipeline.datamanager.train_pixel_sampler.num_rays_per_batch = self.num_rays_per_batch - - # Whether the normals should be estimated based on the point cloud. - estimate_normals = self.normal_method == "open3d" - if self.obb_center is not None and self.obb_rotation is not None and self.obb_scale is not None: - crop_obb = OrientedBox.from_params(self.obb_center, self.obb_rotation, self.obb_scale) - else: - crop_obb = None - - pcd = generate_point_cloud( - pipeline=pipeline, - num_points=self.num_points, - remove_outliers=self.remove_outliers, - reorient_normals=self.reorient_normals, - estimate_normals=estimate_normals, - rgb_output_name=self.rgb_output_name, - depth_output_name=self.depth_output_name, - normal_output_name=self.normal_output_name if self.normal_method == "model_output" else None, - crop_obb=crop_obb, - std_ratio=self.std_ratio, - ) - torch.cuda.empty_cache() - CONSOLE.print(f"[bold green]:white_check_mark: Generated {pcd}") - - if self.save_point_cloud: - CONSOLE.print("Saving Point Cloud...") - o3d.io.write_point_cloud(str(self.output_dir / "point_cloud.ply"), pcd) - print("\033[A\033[A") - CONSOLE.print("[bold green]:white_check_mark: Saving Point Cloud") - - CONSOLE.print("Computing Mesh... this may take a while.") - mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=9) - vertices_to_remove = densities < np.quantile(densities, 0.1) - mesh.remove_vertices_by_mask(vertices_to_remove) - print("\033[A\033[A") - CONSOLE.print("[bold green]:white_check_mark: Computing Mesh") - - CONSOLE.print("Saving Mesh...") - o3d.io.write_triangle_mesh(str(self.output_dir / "poisson_mesh.ply"), mesh) - print("\033[A\033[A") - CONSOLE.print("[bold green]:white_check_mark: Saving Mesh") - - # This will texture the mesh with NeRF and export to a mesh.obj file - # and a material and texture file - if self.texture_method == "nerf": - # load the mesh from the poisson reconstruction - mesh = get_mesh_from_filename( - str(self.output_dir / "poisson_mesh.ply"), target_num_faces=self.target_num_faces - ) - CONSOLE.print("Texturing mesh with NeRF") - texture_utils.export_textured_mesh( - mesh, - pipeline, - self.output_dir, - px_per_uv_triangle=self.px_per_uv_triangle if self.unwrap_method == "custom" else None, - unwrap_method=self.unwrap_method, - num_pixels_per_side=self.num_pixels_per_side, - ) - - -@dataclass -class ExportMarchingCubesMesh(Exporter): - """Export a mesh using marching cubes.""" - - isosurface_threshold: float = 0.0 - """The isosurface threshold for extraction. For SDF based methods the surface is the zero level set.""" - resolution: int = 1024 - """Marching cube resolution.""" - simplify_mesh: bool = False - """Whether to simplify the mesh.""" - bounding_box_min: Tuple[float, float, float] = (-1.0, -1.0, -1.0) - """Minimum of the bounding box.""" - bounding_box_max: Tuple[float, float, float] = (1.0, 1.0, 1.0) - """Maximum of the bounding box.""" - px_per_uv_triangle: int = 4 - """Number of pixels per UV triangle.""" - unwrap_method: Literal["xatlas", "custom"] = "xatlas" - """The method to use for unwrapping the mesh.""" - num_pixels_per_side: int = 2048 - """If using xatlas for unwrapping, the pixels per side of the texture image.""" - target_num_faces: Optional[int] = 50000 - """Target number of faces for the mesh to texture.""" - - def main(self) -> None: - """Main function.""" - if not self.output_dir.exists(): - self.output_dir.mkdir(parents=True) - - _, pipeline, _, _ = eval_setup(self.load_config) - - # TODO: Make this work with Density Field - assert hasattr(pipeline.model.config, "sdf_field"), "Model must have an SDF field." - - CONSOLE.print("Extracting mesh with marching cubes... which may take a while") - - assert self.resolution % 512 == 0, f"""resolution must be divisible by 512, got {self.resolution}. - This is important because the algorithm uses a multi-resolution approach - to evaluate the SDF where the minimum resolution is 512.""" - - # Extract mesh using marching cubes for sdf at a multi-scale resolution. - multi_res_mesh = generate_mesh_with_multires_marching_cubes( - geometry_callable_field=lambda x: cast(SDFField, pipeline.model.field) - .forward_geonetwork(x)[:, 0] - .contiguous(), - resolution=self.resolution, - bounding_box_min=self.bounding_box_min, - bounding_box_max=self.bounding_box_max, - isosurface_threshold=self.isosurface_threshold, - coarse_mask=None, - ) - filename = self.output_dir / "sdf_marching_cubes_mesh.ply" - multi_res_mesh.export(filename) - - # load the mesh from the marching cubes export - mesh = get_mesh_from_filename(str(filename), target_num_faces=self.target_num_faces) - CONSOLE.print("Texturing mesh with NeRF...") - texture_utils.export_textured_mesh( - mesh, - pipeline, - self.output_dir, - px_per_uv_triangle=self.px_per_uv_triangle if self.unwrap_method == "custom" else None, - unwrap_method=self.unwrap_method, - num_pixels_per_side=self.num_pixels_per_side, - ) - - -@dataclass -class ExportCameraPoses(Exporter): - """ - Export camera poses to a .json file. - """ - - def main(self) -> None: - """Export camera poses""" - if not self.output_dir.exists(): - self.output_dir.mkdir(parents=True) - - _, pipeline, _, _ = eval_setup(self.load_config) - assert isinstance(pipeline, VanillaPipeline) - train_frames, eval_frames = collect_camera_poses(pipeline) - - for file_name, frames in [("transforms_train.json", train_frames), ("transforms_eval.json", eval_frames)]: - if len(frames) == 0: - CONSOLE.print(f"[bold yellow]No frames found for {file_name}. Skipping.") - continue - - output_file_path = os.path.join(self.output_dir, file_name) - - with open(output_file_path, "w", encoding="UTF-8") as f: - json.dump(frames, f, indent=4) - - CONSOLE.print(f"[bold green]:white_check_mark: Saved poses to {output_file_path}") - - -@dataclass -class ExportGaussianSplat(Exporter): - """ - Export 3D Gaussian Splatting model to a .ply - """ - - output_filename: str = "splat.ply" - """Name of the output file.""" - obb_center: Optional[Tuple[float, float, float]] = None - """Center of the oriented bounding box.""" - obb_rotation: Optional[Tuple[float, float, float]] = None - """Rotation of the oriented bounding box. Expressed as RPY Euler angles in radians""" - obb_scale: Optional[Tuple[float, float, float]] = None - """Scale of the oriented bounding box along each axis.""" - ply_color_mode: Literal["sh_coeffs", "rgb"] = "sh_coeffs" - """If "rgb", export colors as red/green/blue fields. Otherwise, export colors as - spherical harmonics coefficients.""" - - @staticmethod - def write_ply( - filename: str, - count: int, - map_to_tensors: typing.OrderedDict[str, np.ndarray], - ): - """ - Writes a PLY file with given vertex properties and a tensor of float or uint8 values in the order specified by the OrderedDict. - Note: All float values will be converted to float32 for writing. - - Parameters: - filename (str): The name of the file to write. - count (int): The number of vertices to write. - map_to_tensors (OrderedDict[str, np.ndarray]): An ordered dictionary mapping property names to numpy arrays of float or uint8 values. - Each array should be 1-dimensional and of equal length matching 'count'. Arrays should not be empty. - """ - - # Ensure count matches the length of all tensors - if not all(tensor.size == count for tensor in map_to_tensors.values()): - raise ValueError("Count does not match the length of all tensors") - - # Type check for numpy arrays of type float or uint8 and non-empty - if not all( - isinstance(tensor, np.ndarray) - and (tensor.dtype.kind == "f" or tensor.dtype == np.uint8) - and tensor.size > 0 - for tensor in map_to_tensors.values() - ): - raise ValueError("All tensors must be numpy arrays of float or uint8 type and not empty") - - with open(filename, "wb") as ply_file: - nerfstudio_version = version("nerfstudio") - # Write PLY header - ply_file.write(b"ply\n") - ply_file.write(b"format binary_little_endian 1.0\n") - ply_file.write(f"comment Generated by Nerstudio {nerfstudio_version}\n".encode()) - ply_file.write(b"comment Vertical Axis: z\n") - ply_file.write(f"element vertex {count}\n".encode()) - - # Write properties, in order due to OrderedDict - for key, tensor in map_to_tensors.items(): - data_type = "float" if tensor.dtype.kind == "f" else "uchar" - ply_file.write(f"property {data_type} {key}\n".encode()) - - ply_file.write(b"end_header\n") - - # Write binary data - # Note: If this is a performance bottleneck consider using numpy.hstack for efficiency improvement - for i in range(count): - for tensor in map_to_tensors.values(): - value = tensor[i] - if tensor.dtype.kind == "f": - ply_file.write(np.float32(value).tobytes()) - elif tensor.dtype == np.uint8: - ply_file.write(value.tobytes()) - - def main(self) -> None: - if not self.output_dir.exists(): - self.output_dir.mkdir(parents=True) - - _, pipeline, _, _ = eval_setup(self.load_config, test_mode="inference") - - assert isinstance(pipeline.model, SplatfactoModel) - - model: SplatfactoModel = pipeline.model - - filename = self.output_dir / self.output_filename - - map_to_tensors = OrderedDict() - - with torch.no_grad(): - positions = model.means.cpu().numpy() - count = positions.shape[0] - n = count - map_to_tensors["x"] = positions[:, 0] - map_to_tensors["y"] = positions[:, 1] - map_to_tensors["z"] = positions[:, 2] - map_to_tensors["nx"] = np.zeros(n, dtype=np.float32) - map_to_tensors["ny"] = np.zeros(n, dtype=np.float32) - map_to_tensors["nz"] = np.zeros(n, dtype=np.float32) - - if self.ply_color_mode == "rgb": - colors = torch.clamp(model.colors.clone(), 0.0, 1.0).data.cpu().numpy() - colors = (colors * 255).astype(np.uint8) - map_to_tensors["red"] = colors[:, 0] - map_to_tensors["green"] = colors[:, 1] - map_to_tensors["blue"] = colors[:, 2] - elif self.ply_color_mode == "sh_coeffs": - shs_0 = model.shs_0.contiguous().cpu().numpy() - for i in range(shs_0.shape[1]): - map_to_tensors[f"f_dc_{i}"] = shs_0[:, i, None] - - if model.config.sh_degree > 0: - if self.ply_color_mode == "rgb": - CONSOLE.print( - "Warning: model has higher level of spherical harmonics, ignoring them and only export rgb." - ) - elif self.ply_color_mode == "sh_coeffs": - # transpose(1, 2) was needed to match the sh order in Inria version - shs_rest = model.shs_rest.transpose(1, 2).contiguous().cpu().numpy() - shs_rest = shs_rest.reshape((n, -1)) - for i in range(shs_rest.shape[-1]): - map_to_tensors[f"f_rest_{i}"] = shs_rest[:, i, None] - - map_to_tensors["opacity"] = model.opacities.data.cpu().numpy() - - scales = model.scales.data.cpu().numpy() - for i in range(3): - map_to_tensors[f"scale_{i}"] = scales[:, i, None] - - quats = model.quats.data.cpu().numpy() - for i in range(4): - map_to_tensors[f"rot_{i}"] = quats[:, i, None] - - if self.obb_center is not None and self.obb_rotation is not None and self.obb_scale is not None: - crop_obb = OrientedBox.from_params(self.obb_center, self.obb_rotation, self.obb_scale) - assert crop_obb is not None - mask = crop_obb.within(torch.from_numpy(positions)).numpy() - for k, t in map_to_tensors.items(): - map_to_tensors[k] = map_to_tensors[k][mask] - - n = map_to_tensors["x"].shape[0] - count = n - - # post optimization, it is possible have NaN/Inf values in some attributes - # to ensure the exported ply file has finite values, we enforce finite filters. - select = np.ones(n, dtype=bool) - for k, t in map_to_tensors.items(): - n_before = np.sum(select) - select = np.logical_and(select, np.isfinite(t).all(axis=-1)) - n_after = np.sum(select) - if n_after < n_before: - CONSOLE.print(f"{n_before - n_after} NaN/Inf elements in {k}") - nan_count = np.sum(select) - n - - # filter gaussians that have opacities < 1/255, because they are skipped in cuda rasterization - low_opacity_gaussians = (map_to_tensors["opacity"]).squeeze(axis=-1) < -5.5373 # logit(1/255) - lowopa_count = np.sum(low_opacity_gaussians) - select[low_opacity_gaussians] = 0 - - if np.sum(select) < n: - CONSOLE.print( - f"{nan_count} Gaussians have NaN/Inf and {lowopa_count} have low opacity, only export {np.sum(select)}/{n}" - ) - for k, t in map_to_tensors.items(): - map_to_tensors[k] = map_to_tensors[k][select] - count = np.sum(select) - - ExportGaussianSplat.write_ply(str(filename), count, map_to_tensors) - - -Commands = tyro.conf.FlagConversionOff[ - Union[ - Annotated[ExportPointCloud, tyro.conf.subcommand(name="pointcloud")], - Annotated[ExportTSDFMesh, tyro.conf.subcommand(name="tsdf")], - Annotated[ExportPoissonMesh, tyro.conf.subcommand(name="poisson")], - Annotated[ExportMarchingCubesMesh, tyro.conf.subcommand(name="marching-cubes")], - Annotated[ExportCameraPoses, tyro.conf.subcommand(name="cameras")], - Annotated[ExportGaussianSplat, tyro.conf.subcommand(name="gaussian-splat")], - ] -] - - -def entrypoint(): - """Entrypoint for use with pyproject scripts.""" - tyro.extras.set_accent_color("bright_yellow") - tyro.cli(Commands).main() - - -if __name__ == "__main__": - entrypoint() - - -def get_parser_fn(): - """Get the parser function for the sphinx docs.""" - return tyro.extras.get_parser(Commands) # noqa From bbed0ca45b07419ac0fb0e54a00ab88e5c8413c0 Mon Sep 17 00:00:00 2001 From: Francesco Christopher Date: Sun, 12 Apr 2026 17:51:06 +0200 Subject: [PATCH 7/8] Release 1.1.6: ns-installer integration, deps-lock baseline, and automated method install workflow --- .gitignore | 339 +- .pre-commit-config.yaml | 26 - .vscode/settings.json | 3 + .../opennerf/opennerf/opennerf_datamanager.py | 113 + .../opennerf/opennerf/opennerf_model.py | 120 + Extra-Methods-Patches/lerf/lerf/__init__.py | 6 + .../lerf/lerf/data/lerf_datamanager.py | 123 + .../lerf/lerf/encoders/clip_encoder.py | 91 + .../lerf/lerf/encoders/openclip_encoder.py | 103 + Extra-Methods-Patches/lerf/lerf/lerf.py | 231 + .../lerf/lerf/lerf_config.py | 175 + .../opennerf/opennerf/opennerf_datamanager.py | 113 + .../opennerf/opennerf/opennerf_model.py | 120 + .../datamanagers/random_subset_datamanager.py | 352 + .../relationfield/relationfield_model.py | 771 ++ .../splatfacto-w/splatfactow/export_script.py | 236 + .../splatfactow/nerfw_dataparser.py | 262 + .../splatfactow/splatfactow_field.py | 174 + .../splatfactow/splatfactow_model.py | 958 ++ .../splatfactow_model.py.tensorpatch | 1435 +++ .../splatfactow_model_patch_minimal.diff | 63 + .../tetra-nerf/CMakeLists.txt | 152 + .../tetra-nerf/cmake/FindCUDA.cmake | 2272 ++++ .../tetra-nerf/cmake/FindOptiX.cmake | 115 + .../tetra-nerf/cmake/FindTorch.cmake | 79 + Extra-Methods-Patches/tetra-nerf/setup.py | 519 + .../tetra-nerf/setup.py.almost-good | 488 + .../tetra-nerf/src/py_binding.cpp | 476 + .../tetra-nerf/src/tetrahedra_tracer.cpp | 926 ++ .../src/tetrahedra_tracer.cpp.patched | 1172 +++ .../tetra-nerf/src/tetrahedra_tracer.h | 433 + .../tetra-nerf/src/utils/vec_math.h | 2635 +++++ .../tetra-nerf/tetranerf/nerfstudio/model.py | 949 ++ .../tetranerf/nerfstudio/pipeline.py | 59 + .../tetranerf/nerfstudio/registration.py | 69 + .../tetranerf/utils/extension/__init__.py | 181 + .../zipnerf-pytorch/extensions/cuda/setup.py | 64 + .../extensions/cuda/setup.py.patch | 12 + .../make_patch_zipnerf_cuda.bat | 55 + .../make_patch_zipnerf_cuda.sh | 52 + .../zipnerf_ns/zipnerf_config.py | 58 + .../zipnerf_ns/zipnerf_datamanager.py | 86 + INSTALL_NOTES.md | 15 + LICENSE | 201 - README_FULL.md | 252 +- auto_install_missing_methods.py | 52 + base.bat | 50 - check_tetranerf_modules.py | 26 + clone_missing_methods.bat | 52 + debug_tetranerf_geometry.py | 415 + deps-lock/.tmp-bulk-install.txt | 2 + deps-lock/.tmp-full-remaining-install.txt | 0 deps-lock/.tmp-full-remaining-skipped.txt | 36 + deps-lock/bootstrap-env.txt | 22 + deps-lock/build-plan.json | 165 + deps-lock/conda-explicit-win-64.txt | 86 + deps-lock/conda-list.json | 4662 +++++++++ deps-lock/installer-selection.json | 12 + deps-lock/lock-meta.json | 19 + deps-lock/msvc-selected.txt | 16 + deps-lock/msvc-toolsets.txt | 11 + deps-lock/nerfstudio-core-overrides.json | 15 + deps-lock/nerfstudio-methods-protected.json | 108 + deps-lock/numpy-compat-audit.txt | 8 + deps-lock/pip-freeze-all.txt | 67 + deps-lock/pip-freeze-replay.txt | 33 + deps_lock.py | 2142 ++++ deps_lock.py.bak | 1883 ++++ docker_notes.md | 37 + doctor.bat | 40 + dump_tetranerf_config.py | 28 + extras_portable_manager.bat | 646 ++ extras_portable_manager.bat.bak | 474 + find_colmap_defaults.py | 13 + find_dataparser_union_defaults.py | 27 + find_patch_field.py | 12 + find_tyro_tuple_issue.py | 27 + freeze_current_env_to_lock.bat | 445 + inspect_tetranerf_cli.py | 36 + inspect_tetranerf_registration.py | 20 + install_all_methods.bat | 20 + install_unix.sh | 183 + install_windows_full_pinned.bat | 640 ++ install_windows_full_pinned.bat.bak | 550 + models/.gitkeep | 0 nerfstudio.code-workspace | 84 - nerfstudio/configs/external_methods.py | 4 +- nerfstudio/exporter/exporter_utils.py | 117 +- nerfstudio/plugins/registry.py | 98 +- nerfstudio/plugins/registry_dataparser.py | 26 +- nerfstudio/scripts/exporter.py | 28 +- nerfstudio/viewer/export_panel.py | 19 +- ...tudio_stable_environment_post_zipnerf.yaml | 319 - ns_installer/__init__.py | 6 + ns_installer/bootstrap.py | 898 ++ ns_installer/build.py | 603 ++ ns_installer/cli.py | 309 + ns_installer/core.py | 245 + ns_installer/deps_lock.py | 7 + ns_installer/doctor.py | 65 + ns_installer/locks.py | 340 + ns_installer/methods_registry.py | 203 + ns_installer/patches.py | 112 + ns_installer/protected.py | 106 + pixi.lock | 9105 ----------------- pixi.toml | 35 - portable_env.bat | 103 + pyproject.toml | 12 +- requirements_pip.txt | 11 +- requirements_post_zipnerf - Copia.txt | 253 - requirements_post_zipnerf.txt | 253 - run-workflow.bat | 0 run_tetranerf.py | 18 + run_tetranerf_direct.py | 20 + run_tetranerf_export.py | 16 + setup.bat | 0 test_cli_v2_pinned.bat | 52 + 117 files changed, 33071 insertions(+), 10610 deletions(-) delete mode 100644 .pre-commit-config.yaml create mode 100644 Extra-Methods-Patches/NeRFtoGSandBack/opennerf/opennerf/opennerf_datamanager.py create mode 100644 Extra-Methods-Patches/NeRFtoGSandBack/opennerf/opennerf/opennerf_model.py create mode 100644 Extra-Methods-Patches/lerf/lerf/__init__.py create mode 100644 Extra-Methods-Patches/lerf/lerf/data/lerf_datamanager.py create mode 100644 Extra-Methods-Patches/lerf/lerf/encoders/clip_encoder.py create mode 100644 Extra-Methods-Patches/lerf/lerf/encoders/openclip_encoder.py create mode 100644 Extra-Methods-Patches/lerf/lerf/lerf.py create mode 100644 Extra-Methods-Patches/lerf/lerf/lerf_config.py create mode 100644 Extra-Methods-Patches/opennerf/opennerf/opennerf_datamanager.py create mode 100644 Extra-Methods-Patches/opennerf/opennerf/opennerf_model.py create mode 100644 Extra-Methods-Patches/pynerf/pynerf/data/datamanagers/random_subset_datamanager.py create mode 100644 Extra-Methods-Patches/relationfield/relationfield/relationfield_model.py create mode 100644 Extra-Methods-Patches/splatfacto-w/splatfactow/export_script.py create mode 100644 Extra-Methods-Patches/splatfacto-w/splatfactow/nerfw_dataparser.py create mode 100644 Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_field.py create mode 100644 Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model.py create mode 100644 Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model.py.tensorpatch create mode 100644 Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model_patch_minimal.diff create mode 100644 Extra-Methods-Patches/tetra-nerf/CMakeLists.txt create mode 100644 Extra-Methods-Patches/tetra-nerf/cmake/FindCUDA.cmake create mode 100644 Extra-Methods-Patches/tetra-nerf/cmake/FindOptiX.cmake create mode 100644 Extra-Methods-Patches/tetra-nerf/cmake/FindTorch.cmake create mode 100644 Extra-Methods-Patches/tetra-nerf/setup.py create mode 100644 Extra-Methods-Patches/tetra-nerf/setup.py.almost-good create mode 100644 Extra-Methods-Patches/tetra-nerf/src/py_binding.cpp create mode 100644 Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.cpp create mode 100644 Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.cpp.patched create mode 100644 Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.h create mode 100644 Extra-Methods-Patches/tetra-nerf/src/utils/vec_math.h create mode 100644 Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/model.py create mode 100644 Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/pipeline.py create mode 100644 Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/registration.py create mode 100644 Extra-Methods-Patches/tetra-nerf/tetranerf/utils/extension/__init__.py create mode 100644 Extra-Methods-Patches/zipnerf-pytorch/extensions/cuda/setup.py create mode 100644 Extra-Methods-Patches/zipnerf-pytorch/extensions/cuda/setup.py.patch create mode 100644 Extra-Methods-Patches/zipnerf-pytorch/make_patch_zipnerf_cuda.bat create mode 100644 Extra-Methods-Patches/zipnerf-pytorch/make_patch_zipnerf_cuda.sh create mode 100644 Extra-Methods-Patches/zipnerf-pytorch/zipnerf_ns/zipnerf_config.py create mode 100644 Extra-Methods-Patches/zipnerf-pytorch/zipnerf_ns/zipnerf_datamanager.py create mode 100644 INSTALL_NOTES.md delete mode 100644 LICENSE create mode 100644 auto_install_missing_methods.py delete mode 100644 base.bat create mode 100644 check_tetranerf_modules.py create mode 100644 clone_missing_methods.bat create mode 100644 debug_tetranerf_geometry.py create mode 100644 deps-lock/.tmp-bulk-install.txt create mode 100644 deps-lock/.tmp-full-remaining-install.txt create mode 100644 deps-lock/.tmp-full-remaining-skipped.txt create mode 100644 deps-lock/bootstrap-env.txt create mode 100644 deps-lock/build-plan.json create mode 100644 deps-lock/conda-explicit-win-64.txt create mode 100644 deps-lock/conda-list.json create mode 100644 deps-lock/installer-selection.json create mode 100644 deps-lock/lock-meta.json create mode 100644 deps-lock/msvc-selected.txt create mode 100644 deps-lock/msvc-toolsets.txt create mode 100644 deps-lock/nerfstudio-core-overrides.json create mode 100644 deps-lock/nerfstudio-methods-protected.json create mode 100644 deps-lock/numpy-compat-audit.txt create mode 100644 deps-lock/pip-freeze-all.txt create mode 100644 deps-lock/pip-freeze-replay.txt create mode 100644 deps_lock.py create mode 100644 deps_lock.py.bak create mode 100644 docker_notes.md create mode 100644 doctor.bat create mode 100644 dump_tetranerf_config.py create mode 100644 extras_portable_manager.bat create mode 100644 extras_portable_manager.bat.bak create mode 100644 find_colmap_defaults.py create mode 100644 find_dataparser_union_defaults.py create mode 100644 find_patch_field.py create mode 100644 find_tyro_tuple_issue.py create mode 100644 freeze_current_env_to_lock.bat create mode 100644 inspect_tetranerf_cli.py create mode 100644 inspect_tetranerf_registration.py create mode 100644 install_all_methods.bat create mode 100644 install_unix.sh create mode 100644 install_windows_full_pinned.bat create mode 100644 install_windows_full_pinned.bat.bak create mode 100644 models/.gitkeep delete mode 100644 nerfstudio.code-workspace delete mode 100644 nerfstudio_stable_environment_post_zipnerf.yaml create mode 100644 ns_installer/__init__.py create mode 100644 ns_installer/bootstrap.py create mode 100644 ns_installer/build.py create mode 100644 ns_installer/cli.py create mode 100644 ns_installer/core.py create mode 100644 ns_installer/deps_lock.py create mode 100644 ns_installer/doctor.py create mode 100644 ns_installer/locks.py create mode 100644 ns_installer/methods_registry.py create mode 100644 ns_installer/patches.py create mode 100644 ns_installer/protected.py delete mode 100644 pixi.lock delete mode 100644 pixi.toml create mode 100644 portable_env.bat delete mode 100644 requirements_post_zipnerf - Copia.txt delete mode 100644 requirements_post_zipnerf.txt create mode 100644 run-workflow.bat create mode 100644 run_tetranerf.py create mode 100644 run_tetranerf_direct.py create mode 100644 run_tetranerf_export.py create mode 100644 setup.bat create mode 100644 test_cli_v2_pinned.bat diff --git a/.gitignore b/.gitignore index a85e0412e7..191383baf3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,218 +1,177 @@ -# Byte-compiled / optimized / DLL files +# ========================================================= +# Core Python / caches +# ========================================================= __pycache__/ +**/__pycache__/ *.py[cod] *$py.class - -# C extensions +*.pyd *.so -# Distribution / packaging -.Python +# ========================================================= +# Build / packaging +# ========================================================= build/ -develop-eggs/ dist/ -downloads/ -!nerfstudio/scripts/downloads/ -eggs/ +site/ .eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg *.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ +*.egg-info/ +pip-wheel-metadata/ +nerfstudio.egg-info/ +wheelhouse/ + +# ========================================================= +# Test / tooling caches +# ========================================================= +# Python caches +__pycache__/ +**/__pycache__/ +*.py[cod] +*$py.class +.pytest_cache/ +.mypy_cache/ +.pyre/ +.pytype/ +.ruff_cache/ +.hypothesis/ .tox/ .nox/ .coverage .coverage.* -.cache -nosetests.xml coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.envrc -.venv -env/ +htmlcov/ +.ipynb_checkpoints/ + +# ========================================================= +# Local environments +# ========================================================= +.conda/ +.conda/** +.venv/ venv/ +env/ ENV/ -env.bak/ -venv.bak/ -.nerfstudio.code-workspace - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ +.env +.env.* +.envrc -# Experiments and outputs +# ========================================================= +# Project-local runtime/cache +# ========================================================= +.cache/ +.cache/** +installation_temp/ + +# ========================================================= +# Editor / OS junk +# ========================================================= +.vscode/ +.idea/ +.DS_Store +Thumbs.db +desktop.ini +*.swp +*.swo + +# ========================================================= +# Logs / temp / backups +# ========================================================= +*.log +*.tmp +*.temp +*.orig +*.bak + +# Keep selected backup files +!deps_lock.py.bak +!install_windows_full_pinned.bat.bak +!extras_portable_manager.bat.bak + +# ========================================================= +# Generated outputs / datasets / models +# ========================================================= outputs/ +outputs/** exports/ -renders/ -# tensorboard log files -events.out.* +exports/** +data/ +data/** -# Data -/data +# Keep models dir itself, but not model contents +models/* +!models/.gitkeep -# Misc -old/ -temp* -!temporal* -.nfs* -external/ -__MACOSX/ -node_modules/ -bash/ -cache/ -package-lock.json -camera_paths/ -.DS_Store -._.DS_Store -*/**/.DS_Store -*/**/._.DS_Store - -#Requirements and test stuff: -# Root-level exclusions -/*.txt -/*.pdf -/*.yml -/*.yaml +# ========================================================= +# Docs build +# ========================================================= +docs/_build/ -# ✅ Exceptions: Include specific files in root dir -!requirements_pip.txt -!requirements_conda.yaml -# External Submodules: +# ========================================================= +# Installer-managed external method repos +# ========================================================= NeRFtoGSandBack/ -glomap/ +NeRFtoGSandBack/** instruct-gs2gs/ +instruct-gs2gs/** +lerf/ +lerf/** opennerf/ -pytorch_scatter/ +opennerf/** +pynerf/ +pynerf/** +relationfield/ +relationfield/** +scenefun3d/ +scenefun3d/** +sdfstudio/ +sdfstudio/** splatfacto-w/ -src/igs2gs/ -src/nerfgs/ -src/splatfacto-w/ -src/zipnerf/ +splatfacto-w/** +splatfacto-w_reforged/ +splatfacto-w_reforged/** tetra-nerf/ +tetra-nerf/** zipnerf-pytorch/ - -# pixi environments -.pixi -/third_party \ No newline at end of file +zipnerf-pytorch/** + +# ========================================================= +# Keep important repo metadata/config tracked +# ========================================================= +!.gitattributes +!.gitignore +!.dockerignore +!.prettierrc.js +!pyproject.toml +!requirements_pip.txt +!requirements_conda.yaml +!README.md +!README_FULL.md +!INSTALL_NOTES.md +!Dockerfile + +# ========================================================= +# Keep reproducibility lock content tracked +# ========================================================= +!deps-lock/ +!deps-lock/** +# ========================================================= +# Keep tests tracked +# ========================================================= +!tests/ +!tests/** +# ========================================================= +# Keep essential source trees tracked +# ========================================================= +!nerfstudio/ +!nerfstudio/** +!ns_installer/ +!ns_installer/** +!Extra-Methods-Patches/ +!Extra-Methods-Patches/** + +# Re-ignore cache dirs inside tracked trees +nerfstudio/**/__pycache__/ +ns_installer/**/__pycache__/ +Extra-Methods-Patches/**/__pycache__/ +tests/**/__pycache__/ \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index a93cfbd1fa..0000000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# See https://pre-commit.com for more information -# See https://pre-commit.com/hooks.html for more hooks -default_language_version: - python: python3 -repos: -- repo: local - hooks: - - id: add-license-headers - name: add-license-headers - entry: nerfstudio/scripts/licensing/license_headers.sh - language: script - files: '.*' - pass_filenames: false -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 - hooks: - - id: trailing-whitespace - - id: end-of-file-fixer -- repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.6.2 - hooks: - - id: ruff - types_or: [ python, pyi, jupyter ] - args: [ --fix ] - - id: ruff-format - types_or: [ python, pyi, jupyter ] diff --git a/.vscode/settings.json b/.vscode/settings.json index c365ae07b4..e561f6663f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -123,4 +123,7 @@ "python.analysis.typeCheckingMode": "basic", "python.analysis.diagnosticMode": "workspace", "eslint.packageManager": "yarn", + "python-envs.defaultEnvManager": "ms-python.python:conda", + "python-envs.defaultPackageManager": "ms-python.python:conda", + "cmake.sourceDirectory": "C:/Users/crist/Documents/nerfstudio_custom/tiny-cuda-nn", } diff --git a/Extra-Methods-Patches/NeRFtoGSandBack/opennerf/opennerf/opennerf_datamanager.py b/Extra-Methods-Patches/NeRFtoGSandBack/opennerf/opennerf/opennerf_datamanager.py new file mode 100644 index 0000000000..d90788ff1e --- /dev/null +++ b/Extra-Methods-Patches/NeRFtoGSandBack/opennerf/opennerf/opennerf_datamanager.py @@ -0,0 +1,113 @@ +# Copyright 2022 The Nerfstudio Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Datamanager. +""" + +from __future__ import annotations + +import os.path as osp +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Dict, List, Literal, Optional, Tuple, Type, Union + +import torch +from nerfstudio.cameras.rays import RayBundle +from rich.progress import Console + +CONSOLE = Console(width=120) + +from opennerf.data.utils.dino_dataloader import DinoDataloader +from opennerf.data.utils.openseg_dataloader import OpenSegDataloader +from nerfstudio.data.datamanagers.base_datamanager import VanillaDataManager, VanillaDataManagerConfig + + +@dataclass +class OpenNerfDataManagerConfig(VanillaDataManagerConfig): + _target: Type = field(default_factory=lambda: OpenNerfDataManager) + patch_tile_size_range: Tuple[float, float] = (0.05, 0.5) + patch_tile_size_res: int = 7 + patch_stride_scaler: float = 0.5 + + +class OpenNerfDataManager(VanillaDataManager): # pylint: disable=abstract-method + """Basic stored data manager implementation. + + This is pretty much a port over from our old dataloading utilities, and is a little jank + under the hood. We may clean this up a little bit under the hood with more standard dataloading + components that can be strung together, but it can be just used as a black box for now since + only the constructor is likely to change in the future, or maybe passing in step number to the + next_train and next_eval functions. + + Args: + config: the DataManagerConfig used to instantiate class + """ + + config: OpenNerfDataManagerConfig + + def __init__( + self, + config: OpenNerfDataManagerConfig, + device: Union[torch.device, str] = "cpu", + test_mode: Literal["test", "val", "inference"] = "val", + world_size: int = 1, + local_rank: int = 0, + **kwargs, # pylint: disable=unused-argument + ): + super().__init__( + config=config, device=device, test_mode=test_mode, world_size=world_size, local_rank=local_rank, **kwargs + ) + + if test_mode == 'inference': + return + + images = [self.train_dataset[i]["image"].permute(2, 0, 1)[None, ...] for i in range(len(self.train_dataset))] + images = torch.cat(images) + + cache_dir = f"outputs/{self.config.dataparser.data.parent.name}/{self.config.dataparser.data.name}" + dino_cache_path = Path(osp.join(cache_dir, "dino.npy")) + openseg_cache_path = Path(osp.join(cache_dir, "openseg.npy")) + # NOTE: cache config is sensitive to list vs. tuple, because it checks for dict equality + image_pathes = self.train_dataset._dataparser_outputs.image_filenames + + self.dino_dataloader = DinoDataloader( + image_list=images, + device=self.device, + cfg={"image_shape": list(images.shape[2:4])}, + cache_path=dino_cache_path, + ) + self.openseg_dataloader = OpenSegDataloader( + image_list=image_pathes, + device=self.device, + cfg={"image_shape": list(images.shape[2:4])}, + cache_path=openseg_cache_path, + ) + torch.cuda.empty_cache() + + def next_train(self, step: int) -> Tuple[RayBundle, Dict]: + """Returns the next batch of data from the train dataloader.""" + self.train_count += 1 + image_batch = next(self.iter_train_image_dataloader) + assert self.train_pixel_sampler is not None + batch = self.train_pixel_sampler.sample(image_batch) + ray_indices = batch["indices"] + ray_bundle = self.train_ray_generator(ray_indices) + batch["dino"] = self.dino_dataloader(ray_indices) + batch["openseg"] = self.openseg_dataloader(ray_indices) + ray_bundle.metadata["fx"] = self.train_dataset.cameras[0].fx.item() + ray_bundle.metadata["width"] = self.train_dataset.cameras[0].width.item() + ray_bundle.metadata["fy"] = self.train_dataset.cameras[0].fy.item() + ray_bundle.metadata["height"] = self.train_dataset.cameras[0].height.item() + return ray_bundle, batch diff --git a/Extra-Methods-Patches/NeRFtoGSandBack/opennerf/opennerf/opennerf_model.py b/Extra-Methods-Patches/NeRFtoGSandBack/opennerf/opennerf/opennerf_model.py new file mode 100644 index 0000000000..b21f2a679c --- /dev/null +++ b/Extra-Methods-Patches/NeRFtoGSandBack/opennerf/opennerf/opennerf_model.py @@ -0,0 +1,120 @@ +from dataclasses import dataclass, field +from typing import Dict, List, Tuple, Type, Literal + +import torch +from nerfstudio.cameras.rays import RayBundle, RaySamples +from nerfstudio.field_components.field_heads import FieldHeadNames +from nerfstudio.models.nerfacto import NerfactoModel, NerfactoModelConfig +from nerfstudio.viewer.server.viewer_elements import * +from torch.nn import Parameter + +from opennerf.opennerf_field import OpenNerfField +from opennerf.opennerf_fieldheadnames import OpenNerfFieldHeadNames +from opennerf.opennerf_renderers import CLIPRenderer, MeanRenderer + + +@dataclass +class OpenNerfModelConfig(NerfactoModelConfig): + _target: Type = field(default_factory=lambda: OpenNerfModel) + clip_loss_weight: float = 0.1 + dino_loss_weight: float = 0.0 + openseg_loss_weight: float = 1.0 + openseg_loss: Literal["Huber", "Cosine", "MSE"] = 'MSE' + n_scales: int = 30 + max_scale: float = 1.5 + """maximum scale used to compute relevancy with""" + num_opennerf_samples: int = 24 + hashgrid_layers: Tuple[int, ...] = (12, 12) + hashgrid_resolutions: Tuple[Tuple[int, int], ...] = ((16, 128), (128, 512)) + hashgrid_sizes: Tuple[int, ...] = (19, 19) + num_hidden_clip_layers: int = 1 + + +class OpenNerfModel(NerfactoModel): + config: OpenNerfModelConfig + + def populate_modules(self): + super().populate_modules() + + self.renderer_clip = CLIPRenderer() + self.renderer_mean = MeanRenderer() + + self.opennerf_field = OpenNerfField( + self.config.hashgrid_layers, + self.config.hashgrid_sizes, + self.config.hashgrid_resolutions, + self.config.num_hidden_clip_layers, + ) + + def get_outputs(self, ray_bundle: RayBundle): + ray_samples, weights_list, ray_samples_list = self.proposal_sampler(ray_bundle, density_fns=self.density_fns) + ray_samples_list.append(ray_samples) + + nerfacto_field_outputs, outputs, weights = self._get_outputs_nerfacto(ray_samples) + opennerf_weights, best_ids = torch.topk(weights, self.config.num_opennerf_samples, dim=-2, sorted=False) + + def gather_fn(tens): + return torch.gather(tens, -2, best_ids.expand(*best_ids.shape[:-1], tens.shape[-1])) + + dataclass_fn = lambda dc: dc._apply_fn_to_fields(gather_fn, dataclass_fn) + opennerf_samples: RaySamples = ray_samples._apply_fn_to_fields(gather_fn, dataclass_fn) + + weights_list.append(weights) + if self.training: + outputs["weights_list"] = weights_list + outputs["ray_samples_list"] = ray_samples_list + + opennerf_field_outputs = self.opennerf_field.get_outputs(opennerf_samples) + + outputs["dino"] = self.renderer_mean( + embeds=opennerf_field_outputs[OpenNerfFieldHeadNames.DINO], weights=opennerf_weights.detach() + ) + outputs["openseg"] = self.renderer_mean( + embeds=opennerf_field_outputs[OpenNerfFieldHeadNames.OPENSEG], weights=opennerf_weights.detach() + ) + + return outputs + + + def _get_outputs_nerfacto(self, ray_samples: RaySamples): + field_outputs = self.field(ray_samples, compute_normals=self.config.predict_normals) + weights = ray_samples.get_weights(field_outputs[FieldHeadNames.DENSITY]) + + FieldHeadNames.UNCERTAINTY + + rgb = self.renderer_rgb(rgb=field_outputs[FieldHeadNames.RGB], weights=weights) + depth = self.renderer_depth(weights=weights, ray_samples=ray_samples) + accumulation = self.renderer_accumulation(weights=weights) + + outputs = { + "rgb": rgb, + "accumulation": accumulation, + "depth": depth, + } + + return field_outputs, outputs, weights + + def get_loss_dict(self, outputs, batch, metrics_dict=None): + loss_dict = super().get_loss_dict(outputs, batch, metrics_dict) + if self.training: + unreduced_dino = self.config.dino_loss_weight * torch.nn.functional.mse_loss( + outputs["dino"], batch["dino"], reduction="none") + loss_dict["dino_loss"] = unreduced_dino.sum(dim=-1).nanmean() + + if self.config.openseg_loss == 'Huber': + unreduced_openseg = self.config.openseg_loss_weight * torch.nn.functional.huber_loss( + outputs["openseg"], batch["openseg"], delta=1.25, reduction="none") + elif self.config.openseg_loss == 'Cosine': + unreduced_openseg = self.config.openseg_loss_weight * (1.0 - torch.nn.functional.cosine_similarity( + outputs["openseg"], batch["openseg"])) + elif self.config.openseg_loss == 'MSE': + unreduced_openseg = self.config.openseg_loss_weight * torch.nn.functional.mse_loss( + outputs["openseg"], batch["openseg"], reduction="none") + + loss_dict["openseg_loss"] = unreduced_openseg.sum(dim=-1).nanmean() + return loss_dict + + def get_param_groups(self) -> Dict[str, List[Parameter]]: + param_groups = super().get_param_groups() + param_groups["opennerf"] = list(self.opennerf_field.parameters()) + return param_groups diff --git a/Extra-Methods-Patches/lerf/lerf/__init__.py b/Extra-Methods-Patches/lerf/lerf/__init__.py new file mode 100644 index 0000000000..5e84f3678d --- /dev/null +++ b/Extra-Methods-Patches/lerf/lerf/__init__.py @@ -0,0 +1,6 @@ +from .lerf import LERFModel, LERFModelConfig + +__all__ = [ + "LERFModel", + "LERFModelConfig", +] \ No newline at end of file diff --git a/Extra-Methods-Patches/lerf/lerf/data/lerf_datamanager.py b/Extra-Methods-Patches/lerf/lerf/data/lerf_datamanager.py new file mode 100644 index 0000000000..09725f9c3d --- /dev/null +++ b/Extra-Methods-Patches/lerf/lerf/data/lerf_datamanager.py @@ -0,0 +1,123 @@ +# Copyright 2022 The Nerfstudio Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Datamanager. +""" + +from __future__ import annotations + +import os.path as osp +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Dict, List, Literal, Optional, Tuple, Type, Union + +import torch +import yaml +from nerfstudio.cameras.rays import RayBundle +from nerfstudio.data.utils.nerfstudio_collate import nerfstudio_collate +from nerfstudio.engine.callbacks import TrainingCallback, TrainingCallbackAttributes +from nerfstudio.model_components.ray_generators import RayGenerator +from nerfstudio.utils.misc import IterableWrapper +from rich.progress import Console + +CONSOLE = Console(width=120) + +from lerf.data.utils.dino_dataloader import DinoDataloader +from lerf.data.utils.pyramid_embedding_dataloader import PyramidEmbeddingDataloader +from lerf.encoders.image_encoder import BaseImageEncoder +from nerfstudio.data.datamanagers.base_datamanager import VanillaDataManager, VanillaDataManagerConfig + + +@dataclass +class LERFDataManagerConfig(VanillaDataManagerConfig): + _target: Type = field(default_factory=lambda: LERFDataManager) + patch_tile_size_range: Tuple[float, float] = (0.05, 0.5) + patch_tile_size_res: int = 7 + patch_stride_scaler: float = 0.5 + + +class LERFDataManager(VanillaDataManager): # pylint: disable=abstract-method + """Basic stored data manager implementation. + + This is pretty much a port over from our old dataloading utilities, and is a little jank + under the hood. We may clean this up a little bit under the hood with more standard dataloading + components that can be strung together, but it can be just used as a black box for now since + only the constructor is likely to change in the future, or maybe passing in step number to the + next_train and next_eval functions. + + Args: + config: the DataManagerConfig used to instantiate class + """ + + config: LERFDataManagerConfig + + def __init__( + self, + config: LERFDataManagerConfig, + device: Union[torch.device, str] = "cpu", + test_mode: Literal["test", "val", "inference"] = "val", + world_size: int = 1, + local_rank: int = 0, + **kwargs, # pylint: disable=unused-argument + ): + super().__init__( + config=config, device=device, test_mode=test_mode, world_size=world_size, local_rank=local_rank, **kwargs + ) + self.image_encoder: BaseImageEncoder = kwargs["image_encoder"] + images = [self.train_dataset[i]["image"].permute(2, 0, 1)[None, ...] for i in range(len(self.train_dataset))] + images = torch.cat(images) + + cache_dir = f"outputs/{self.config.dataparser.data.name}" + clip_cache_path = Path(osp.join(cache_dir, f"clip_{self.image_encoder.name}")) + dino_cache_path = Path(osp.join(cache_dir, "dino.npy")) + # NOTE: cache config is sensitive to list vs. tuple, because it checks for dict equality + self.dino_dataloader = DinoDataloader( + image_list=images, + device=self.device, + cfg={"image_shape": list(images.shape[2:4])}, + cache_path=dino_cache_path, + ) + torch.cuda.empty_cache() + self.clip_interpolator = PyramidEmbeddingDataloader( + image_list=images, + device=self.device, + cfg={ + "tile_size_range": [0.05, 0.5], + "tile_size_res": 7, + "stride_scaler": 0.5, + "image_shape": list(images.shape[2:4]), + "model_name": self.image_encoder.name, + }, + cache_path=clip_cache_path, + model=self.image_encoder, + ) + + def next_train(self, step: int) -> Tuple[RayBundle, Dict]: + """Returns the next batch of data from the train dataloader.""" + self.train_count += 1 + image_batch = next(self.iter_train_image_dataloader) + assert self.train_pixel_sampler is not None + batch = self.train_pixel_sampler.sample(image_batch) + ray_indices = batch["indices"] + ray_bundle = self.train_ray_generator(ray_indices) + batch["clip"], clip_scale = self.clip_interpolator(ray_indices) + batch["dino"] = self.dino_dataloader(ray_indices) + ray_bundle.metadata["clip_scales"] = clip_scale + # assume all cameras have the same focal length and image width + ray_bundle.metadata["fx"] = self.train_dataset.cameras[0].fx.item() + ray_bundle.metadata["width"] = self.train_dataset.cameras[0].width.item() + ray_bundle.metadata["fy"] = self.train_dataset.cameras[0].fy.item() + ray_bundle.metadata["height"] = self.train_dataset.cameras[0].height.item() + return ray_bundle, batch diff --git a/Extra-Methods-Patches/lerf/lerf/encoders/clip_encoder.py b/Extra-Methods-Patches/lerf/lerf/encoders/clip_encoder.py new file mode 100644 index 0000000000..0977f9192c --- /dev/null +++ b/Extra-Methods-Patches/lerf/lerf/encoders/clip_encoder.py @@ -0,0 +1,91 @@ +from dataclasses import dataclass, field +from typing import Tuple, Type + +import torch +import torchvision + +try: + import clip +except ImportError: + assert False, "clip is not installed, install it with `pip install clip`" + +from lerf.encoders.image_encoder import BaseImageEncoder, BaseImageEncoderConfig + + +@dataclass +class CLIPNetworkConfig(BaseImageEncoderConfig): + _target: Type = field(default_factory=lambda: CLIPNetwork) + clip_model_type: str = "ViT-B/16" + clip_n_dims: int = 512 + negatives: Tuple[str, ...] = ("object", "things", "stuff", "texture") + + +class CLIPNetwork(BaseImageEncoder): + def __init__(self, config: CLIPNetworkConfig): + super().__init__() + self.config = config + self.process = torchvision.transforms.Compose( + [ + torchvision.transforms.Resize((224, 224)), + torchvision.transforms.Normalize( + mean=[0.48145466, 0.4578275, 0.40821073], + std=[0.26862954, 0.26130258, 0.27577711], + ), + ] + ) + model, _ = clip.load(self.config.clip_model_type) + model.eval() + self.tokenizer = clip.tokenize + self.model = model.to("cuda") + self.clip_n_dims = self.config.clip_n_dims + + self.positives = ["hand sanitizer"] + self.negatives = self.config.negatives + with torch.no_grad(): + tok_phrases = torch.cat([self.tokenizer(phrase) for phrase in self.positives]).to("cuda") + self.pos_embeds = model.encode_text(tok_phrases) + tok_phrases = torch.cat([self.tokenizer(phrase) for phrase in self.negatives]).to("cuda") + self.neg_embeds = model.encode_text(tok_phrases) + self.pos_embeds /= self.pos_embeds.norm(dim=-1, keepdim=True) + self.neg_embeds /= self.neg_embeds.norm(dim=-1, keepdim=True) + + assert ( + self.pos_embeds.shape[1] == self.neg_embeds.shape[1] + ), "Positive and negative embeddings must have the same dimensionality" + assert ( + self.pos_embeds.shape[1] == self.clip_n_dims + ), "Embedding dimensionality must match the model dimensionality" + + @property + def name(self) -> str: + return "clip_openai_{}".format(self.config.clip_model_type) + + @property + def embedding_dim(self) -> int: + return self.config.clip_n_dims + + def set_positives(self, text_list): + self.positives = text_list + with torch.no_grad(): + tok_phrases = torch.cat([self.tokenizer(phrase) for phrase in self.positives]).to("cuda") + self.pos_embeds = self.model.encode_text(tok_phrases) + self.pos_embeds /= self.pos_embeds.norm(dim=-1, keepdim=True) + + def get_relevancy(self, embed: torch.Tensor, positive_id: int) -> torch.Tensor: + phrases_embeds = torch.cat([self.pos_embeds, self.neg_embeds], dim=0) + p = phrases_embeds.to(embed.dtype) # phrases x 512 + output = torch.mm(embed, p.T) # rays x phrases + positive_vals = output[..., positive_id : positive_id + 1] # rays x 1 + negative_vals = output[..., len(self.positives) :] # rays x N_phrase + repeated_pos = positive_vals.repeat(1, len(self.negatives)) # rays x N_phrase + + sims = torch.stack((repeated_pos, negative_vals), dim=-1) # rays x N-phrase x 2 + softmax = torch.softmax(10 * sims, dim=-1) # rays x n-phrase x 2 + best_id = softmax[..., 0].argmin(dim=1) # rays x 2 + return torch.gather(softmax, 1, best_id[..., None, None].expand(best_id.shape[0], len(self.negatives), 2))[ + :, 0, : + ] + + def encode_image(self, input): + processed_input = self.process(input).half() + return self.model.encode_image(processed_input) diff --git a/Extra-Methods-Patches/lerf/lerf/encoders/openclip_encoder.py b/Extra-Methods-Patches/lerf/lerf/encoders/openclip_encoder.py new file mode 100644 index 0000000000..4f58cb9406 --- /dev/null +++ b/Extra-Methods-Patches/lerf/lerf/encoders/openclip_encoder.py @@ -0,0 +1,103 @@ +from dataclasses import dataclass, field +from typing import Tuple, Type + +import torch +import torchvision + +try: + import open_clip +except ImportError: + assert False, "open_clip is not installed, install it with `pip install open-clip-torch`" + +from lerf.encoders.image_encoder import (BaseImageEncoder, + BaseImageEncoderConfig) +from nerfstudio.viewer.viewer_elements import ViewerText + + +@dataclass +class OpenCLIPNetworkConfig(BaseImageEncoderConfig): + _target: Type = field(default_factory=lambda: OpenCLIPNetwork) + clip_model_type: str = "ViT-B-16" + clip_model_pretrained: str = "laion2b_s34b_b88k" + clip_n_dims: int = 512 + negatives: Tuple[str, ...] = ("object", "things", "stuff", "texture") + + +class OpenCLIPNetwork(BaseImageEncoder): + def __init__(self, config: OpenCLIPNetworkConfig): + super().__init__() + self.config = config + self.process = torchvision.transforms.Compose( + [ + torchvision.transforms.Resize((224, 224)), + torchvision.transforms.Normalize( + mean=[0.48145466, 0.4578275, 0.40821073], + std=[0.26862954, 0.26130258, 0.27577711], + ), + ] + ) + model, _, _ = open_clip.create_model_and_transforms( + self.config.clip_model_type, # e.g., ViT-B-16 + pretrained=self.config.clip_model_pretrained, # e.g., laion2b_s34b_b88k + precision="fp16", + ) + model.eval() + self.tokenizer = open_clip.get_tokenizer(self.config.clip_model_type) + self.model = model.to("cuda") + self.clip_n_dims = self.config.clip_n_dims + + self.positive_input = ViewerText("LERF Positives", "", cb_hook=self.gui_cb) + + self.positives = self.positive_input.value.split(";") + self.negatives = self.config.negatives + with torch.no_grad(): + tok_phrases = torch.cat([self.tokenizer(phrase) for phrase in self.positives]).to("cuda") + self.pos_embeds = model.encode_text(tok_phrases) + tok_phrases = torch.cat([self.tokenizer(phrase) for phrase in self.negatives]).to("cuda") + self.neg_embeds = model.encode_text(tok_phrases) + self.pos_embeds /= self.pos_embeds.norm(dim=-1, keepdim=True) + self.neg_embeds /= self.neg_embeds.norm(dim=-1, keepdim=True) + + assert ( + self.pos_embeds.shape[1] == self.neg_embeds.shape[1] + ), "Positive and negative embeddings must have the same dimensionality" + assert ( + self.pos_embeds.shape[1] == self.clip_n_dims + ), "Embedding dimensionality must match the model dimensionality" + + @property + def name(self) -> str: + return "openclip_{}_{}".format(self.config.clip_model_type, self.config.clip_model_pretrained) + + @property + def embedding_dim(self) -> int: + return self.config.clip_n_dims + + def gui_cb(self,element): + self.set_positives(element.value.split(";")) + + def set_positives(self, text_list): + self.positives = text_list + with torch.no_grad(): + tok_phrases = torch.cat([self.tokenizer(phrase) for phrase in self.positives]).to("cuda") + self.pos_embeds = self.model.encode_text(tok_phrases) + self.pos_embeds /= self.pos_embeds.norm(dim=-1, keepdim=True) + + def get_relevancy(self, embed: torch.Tensor, positive_id: int) -> torch.Tensor: + phrases_embeds = torch.cat([self.pos_embeds, self.neg_embeds], dim=0) + p = phrases_embeds.to(embed.dtype) # phrases x 512 + output = torch.mm(embed, p.T) # rays x phrases + positive_vals = output[..., positive_id : positive_id + 1] # rays x 1 + negative_vals = output[..., len(self.positives) :] # rays x N_phrase + repeated_pos = positive_vals.repeat(1, len(self.negatives)) # rays x N_phrase + + sims = torch.stack((repeated_pos, negative_vals), dim=-1) # rays x N-phrase x 2 + softmax = torch.softmax(10 * sims, dim=-1) # rays x n-phrase x 2 + best_id = softmax[..., 0].argmin(dim=1) # rays x 2 + return torch.gather(softmax, 1, best_id[..., None, None].expand(best_id.shape[0], len(self.negatives), 2))[ + :, 0, : + ] + + def encode_image(self, input): + processed_input = self.process(input).half() + return self.model.encode_image(processed_input) diff --git a/Extra-Methods-Patches/lerf/lerf/lerf.py b/Extra-Methods-Patches/lerf/lerf/lerf.py new file mode 100644 index 0000000000..f3ea674340 --- /dev/null +++ b/Extra-Methods-Patches/lerf/lerf/lerf.py @@ -0,0 +1,231 @@ +from collections import defaultdict +from dataclasses import dataclass, field +from typing import Dict, List, Tuple, Type + +import numpy as np +import open_clip +import torch +from nerfstudio.cameras.rays import RayBundle, RaySamples +from nerfstudio.data.scene_box import SceneBox +from nerfstudio.field_components.field_heads import FieldHeadNames +from nerfstudio.field_components.spatial_distortions import SceneContraction +from nerfstudio.model_components.ray_samplers import PDFSampler +from nerfstudio.model_components.renderers import DepthRenderer +from nerfstudio.models.nerfacto import NerfactoModel, NerfactoModelConfig +from nerfstudio.utils.colormaps import ColormapOptions, apply_colormap +from nerfstudio.viewer.viewer_elements import * +from torch.nn import Parameter + +from lerf.encoders.image_encoder import BaseImageEncoder +from lerf.lerf_field import LERFField +from lerf.lerf_fieldheadnames import LERFFieldHeadNames +from lerf.lerf_renderers import CLIPRenderer, MeanRenderer + + +@dataclass +class LERFModelConfig(NerfactoModelConfig): + _target: Type = field(default_factory=lambda: LERFModel) + clip_loss_weight: float = 0.1 + n_scales: int = 30 + max_scale: float = 1.5 + """maximum scale used to compute relevancy with""" + num_lerf_samples: int = 24 + hashgrid_layers: Tuple[int, ...] = (12, 12) + hashgrid_resolutions: Tuple[Tuple[int, int], ...] = ((16, 128), (128, 512)) + hashgrid_sizes: Tuple[int, ...] = (19, 19) + +class LERFModel(NerfactoModel): + config: LERFModelConfig + + def populate_modules(self): + super().populate_modules() + + self.renderer_clip = CLIPRenderer() + self.renderer_mean = MeanRenderer() + + self.image_encoder: BaseImageEncoder = self.kwargs["image_encoder"] + self.lerf_field = LERFField( + self.config.hashgrid_layers, + self.config.hashgrid_sizes, + self.config.hashgrid_resolutions, + clip_n_dims=self.image_encoder.embedding_dim, + ) + + def get_max_across(self, ray_samples, weights, hashgrid_field, scales_shape, preset_scales=None): + # TODO smoothen this out + if preset_scales is not None: + assert len(preset_scales) == len(self.image_encoder.positives) + scales_list = torch.tensor(preset_scales) + else: + scales_list = torch.linspace(0.0, self.config.max_scale, self.config.n_scales) + + # probably not a good idea bc it's prob going to be a lot of memory + n_phrases = len(self.image_encoder.positives) + n_phrases_maxs = [None for _ in range(n_phrases)] + n_phrases_sims = [None for _ in range(n_phrases)] + for i, scale in enumerate(scales_list): + scale = scale.item() + with torch.no_grad(): + clip_output = self.lerf_field.get_output_from_hashgrid( + ray_samples, + hashgrid_field, + torch.full(scales_shape, scale, device=weights.device, dtype=hashgrid_field.dtype), + ) + clip_output = self.renderer_clip(embeds=clip_output, weights=weights.detach()) + + for j in range(n_phrases): + if preset_scales is None or j == i: + probs = self.image_encoder.get_relevancy(clip_output, j) + pos_prob = probs[..., 0:1] + if n_phrases_maxs[j] is None or pos_prob.max() > n_phrases_sims[j].max(): + n_phrases_maxs[j] = scale + n_phrases_sims[j] = pos_prob + return torch.stack(n_phrases_sims), torch.Tensor(n_phrases_maxs) + + def get_outputs(self, ray_bundle: RayBundle): + if self.training: + self.camera_optimizer.apply_to_raybundle(ray_bundle) + ray_samples, weights_list, ray_samples_list = self.proposal_sampler(ray_bundle, density_fns=self.density_fns) + ray_samples_list.append(ray_samples) + + nerfacto_field_outputs, outputs, weights = self._get_outputs_nerfacto(ray_samples) + lerf_weights, best_ids = torch.topk(weights, self.config.num_lerf_samples, dim=-2, sorted=False) + + def gather_fn(tens): + return torch.gather(tens, -2, best_ids.expand(*best_ids.shape[:-1], tens.shape[-1])) + + dataclass_fn = lambda dc: dc._apply_fn_to_fields(gather_fn, dataclass_fn) + lerf_samples: RaySamples = ray_samples._apply_fn_to_fields(gather_fn, dataclass_fn) + + if self.training: + with torch.no_grad(): + clip_scales = ray_bundle.metadata["clip_scales"] + clip_scales = clip_scales[..., None] + dist = (lerf_samples.frustums.get_positions() - ray_bundle.origins[:, None, :]).norm( + dim=-1, keepdim=True + ) + clip_scales = clip_scales * ray_bundle.metadata["height"] * (dist / ray_bundle.metadata["fy"]) + else: + clip_scales = torch.ones_like(lerf_samples.spacing_starts, device=self.device) + + override_scales = ( + None if "override_scales" not in ray_bundle.metadata else ray_bundle.metadata["override_scales"] + ) + weights_list.append(weights) + if self.training: + outputs["weights_list"] = weights_list + outputs["ray_samples_list"] = ray_samples_list + for i in range(self.config.num_proposal_iterations): + outputs[f"prop_depth_{i}"] = self.renderer_depth(weights=weights_list[i], ray_samples=ray_samples_list[i]) + + lerf_field_outputs = self.lerf_field.get_outputs(lerf_samples, clip_scales) + outputs["clip"] = self.renderer_clip( + embeds=lerf_field_outputs[LERFFieldHeadNames.CLIP], weights=lerf_weights.detach() + ) + outputs["dino"] = self.renderer_mean( + embeds=lerf_field_outputs[LERFFieldHeadNames.DINO], weights=lerf_weights.detach() + ) + + if not self.training: + with torch.no_grad(): + max_across, best_scales = self.get_max_across( + lerf_samples, + lerf_weights, + lerf_field_outputs[LERFFieldHeadNames.HASHGRID], + clip_scales.shape, + preset_scales=override_scales, + ) + outputs["raw_relevancy"] = max_across # N x B x 1 + outputs["best_scales"] = best_scales.to(self.device) # N + + return outputs + + @torch.no_grad() + def get_outputs_for_camera_ray_bundle(self, camera_ray_bundle: RayBundle) -> Dict[str, torch.Tensor]: + """Takes in camera parameters and computes the output of the model. + + LERF overrides this from base_model since we need to compute the max_across relevancy in multiple batches, + which are not independent since they need to use the same scale + Args: + camera_ray_bundle: ray bundle to calculate outputs over + """ + # TODO(justin) implement max across behavior + num_rays_per_chunk = self.config.eval_num_rays_per_chunk + image_height, image_width = camera_ray_bundle.origins.shape[:2] + num_rays = len(camera_ray_bundle) + outputs_lists = defaultdict(list) # dict from name:list of outputs (1 per bundle) + for i in range(0, num_rays, num_rays_per_chunk): + start_idx = i + end_idx = i + num_rays_per_chunk + ray_bundle = camera_ray_bundle.get_row_major_sliced_ray_bundle(start_idx, end_idx) + outputs = self.forward(ray_bundle=ray_bundle) + # take the best scale for each query across each ray bundle + if i == 0: + best_scales = outputs["best_scales"] + best_relevancies = [m.max() for m in outputs["raw_relevancy"]] + else: + for phrase_i in range(outputs["best_scales"].shape[0]): + m = outputs["raw_relevancy"][phrase_i, ...].max() + if m > best_relevancies[phrase_i]: + best_scales[phrase_i] = outputs["best_scales"][phrase_i] + best_relevancies[phrase_i] = m + # re-render the max_across outputs using the best scales across all batches + for i in range(0, num_rays, num_rays_per_chunk): + start_idx = i + end_idx = i + num_rays_per_chunk + ray_bundle = camera_ray_bundle.get_row_major_sliced_ray_bundle(start_idx, end_idx) + ray_bundle.metadata["override_scales"] = best_scales + outputs = self.forward(ray_bundle=ray_bundle) + # standard nerfstudio concatting + for output_name, output in outputs.items(): # type: ignore + if output_name == "best_scales": + continue + if output_name == "raw_relevancy": + for r_id in range(output.shape[0]): + outputs_lists[f"relevancy_{r_id}"].append(output[r_id, ...]) + else: + outputs_lists[output_name].append(output) + outputs = {} + for output_name, outputs_list in outputs_lists.items(): + if not torch.is_tensor(outputs_list[0]): + # TODO: handle lists of tensors as well + continue + outputs[output_name] = torch.cat(outputs_list).view(image_height, image_width, -1) # type: ignore + for i in range(len(self.image_encoder.positives)): + p_i = torch.clip(outputs[f"relevancy_{i}"] - 0.5, 0, 1) + outputs[f"composited_{i}"] = apply_colormap(p_i / (p_i.max() + 1e-6), ColormapOptions("turbo")) + mask = (outputs["relevancy_0"] < 0.5).squeeze() + outputs[f"composited_{i}"][mask, :] = outputs["rgb"][mask, :] + return outputs + + def _get_outputs_nerfacto(self, ray_samples: RaySamples): + field_outputs = self.field(ray_samples, compute_normals=self.config.predict_normals) + weights = ray_samples.get_weights(field_outputs[FieldHeadNames.DENSITY]) + + rgb = self.renderer_rgb(rgb=field_outputs[FieldHeadNames.RGB], weights=weights) + depth = self.renderer_depth(weights=weights, ray_samples=ray_samples) + accumulation = self.renderer_accumulation(weights=weights) + + outputs = { + "rgb": rgb, + "accumulation": accumulation, + "depth": depth, + } + + return field_outputs, outputs, weights + + def get_loss_dict(self, outputs, batch, metrics_dict=None): + loss_dict = super().get_loss_dict(outputs, batch, metrics_dict) + if self.training: + unreduced_clip = self.config.clip_loss_weight * torch.nn.functional.huber_loss( + outputs["clip"], batch["clip"], delta=1.25, reduction="none" + ) + loss_dict["clip_loss"] = unreduced_clip.sum(dim=-1).nanmean() + unreduced_dino = torch.nn.functional.mse_loss(outputs["dino"], batch["dino"], reduction="none") + loss_dict["dino_loss"] = unreduced_dino.sum(dim=-1).nanmean() + return loss_dict + + def get_param_groups(self) -> Dict[str, List[Parameter]]: + param_groups = super().get_param_groups() + param_groups["lerf"] = list(self.lerf_field.parameters()) + return param_groups diff --git a/Extra-Methods-Patches/lerf/lerf/lerf_config.py b/Extra-Methods-Patches/lerf/lerf/lerf_config.py new file mode 100644 index 0000000000..2bf1001af8 --- /dev/null +++ b/Extra-Methods-Patches/lerf/lerf/lerf_config.py @@ -0,0 +1,175 @@ +""" +LERF configuration file. +""" + +from nerfstudio.cameras.camera_optimizers import CameraOptimizerConfig +from nerfstudio.configs.base_config import ViewerConfig +from nerfstudio.data.dataparsers.nerfstudio_dataparser import NerfstudioDataParserConfig +from nerfstudio.engine.optimizers import AdamOptimizerConfig, RAdamOptimizerConfig +from nerfstudio.engine.schedulers import ExponentialDecaySchedulerConfig +from nerfstudio.engine.trainer import TrainerConfig +from nerfstudio.plugins.types import MethodSpecification + +from lerf.data.lerf_datamanager import LERFDataManagerConfig +from lerf.lerf.lerf import LERFModelConfig +from lerf.lerf_pipeline import LERFPipelineConfig +""" +Swap out the network config to use OpenCLIP or CLIP here. +""" +from lerf.encoders.clip_encoder import CLIPNetworkConfig +from lerf.encoders.openclip_encoder import OpenCLIPNetworkConfig + +lerf_method = MethodSpecification( + config=TrainerConfig( + method_name="lerf", + steps_per_eval_batch=500, + steps_per_save=2000, + max_num_iterations=30000, + mixed_precision=True, + pipeline=LERFPipelineConfig( + datamanager=LERFDataManagerConfig( + dataparser=NerfstudioDataParserConfig(train_split_fraction=0.99), + train_num_rays_per_batch=4096, + eval_num_rays_per_batch=4096, + ), + model=LERFModelConfig( + eval_num_rays_per_chunk=1 << 15, + # NOTE: exceeding 16 layers per hashgrid causes a segfault within Tiny CUDA NN, so instead we compose multiple hashgrids together + hashgrid_sizes=(19, 19), + hashgrid_layers=(12, 12), + hashgrid_resolutions=((16, 128), (128, 512)), + num_lerf_samples=24, + ), + network=OpenCLIPNetworkConfig( + clip_model_type="ViT-B-16", clip_model_pretrained="laion2b_s34b_b88k", clip_n_dims=512 + ), + # You can swap the type of input encoder by specifying different NetworkConfigs, the one below uses OpenAI CLIP, the one above uses OpenCLIP + # network=CLIPNetworkConfig( + # clip_model_type="ViT-B/16", clip_n_dims=512 + # ) + ), + optimizers={ + "proposal_networks": { + "optimizer": AdamOptimizerConfig(lr=1e-2, eps=1e-15), + "scheduler": None, + }, + "fields": { + "optimizer": AdamOptimizerConfig(lr=1e-2, eps=1e-15), + "scheduler": ExponentialDecaySchedulerConfig(lr_final=1e-3, max_steps=30000), + }, + "lerf": { + "optimizer": RAdamOptimizerConfig(lr=1e-2, eps=1e-15, weight_decay=1e-9), + "scheduler": ExponentialDecaySchedulerConfig(lr_final=1e-3, max_steps=4000), + }, + "camera_opt": { + "optimizer": AdamOptimizerConfig(lr=1e-3, eps=1e-15), + "scheduler": ExponentialDecaySchedulerConfig( + lr_final=1e-4, max_steps=5000 + ), + }, + }, + viewer=ViewerConfig(num_rays_per_chunk=1 << 15), + vis="viewer", + ), + description="Base config for LERF", +) +lerf_method_big = MethodSpecification( + config=TrainerConfig( + method_name="lerf-big", + steps_per_eval_batch=500, + steps_per_save=2000, + max_num_iterations=30000, + mixed_precision=True, + pipeline=LERFPipelineConfig( + datamanager=LERFDataManagerConfig( + dataparser=NerfstudioDataParserConfig(train_split_fraction=0.99), + train_num_rays_per_batch=4096, + eval_num_rays_per_batch=4096, + ), + model=LERFModelConfig( + eval_num_rays_per_chunk=1 << 15, + # NOTE: exceeding 16 layers per hashgrid causes a segfault within Tiny CUDA NN, so instead we compose multiple hashgrids together + hashgrid_sizes=(19, 19), + hashgrid_layers=(16, 16), + hashgrid_resolutions=((16, 128), (128, 512)), + num_lerf_samples=32, + ), + network=OpenCLIPNetworkConfig( + clip_model_type="ViT-L-14", clip_model_pretrained="laion2b_s32b_b82k", clip_n_dims=768 + ), + ), + optimizers={ + "proposal_networks": { + "optimizer": AdamOptimizerConfig(lr=1e-2, eps=1e-15), + "scheduler": None, + }, + "fields": { + "optimizer": AdamOptimizerConfig(lr=1e-2, eps=1e-15), + "scheduler": ExponentialDecaySchedulerConfig(lr_final=1e-3, max_steps=30000), + }, + "lerf": { + "optimizer": RAdamOptimizerConfig(lr=1e-2, eps=1e-15, weight_decay=1e-9), + "scheduler": ExponentialDecaySchedulerConfig(lr_final=1e-3, max_steps=3000), + }, + "camera_opt": { + "optimizer": AdamOptimizerConfig(lr=1e-3, eps=1e-15), + "scheduler": ExponentialDecaySchedulerConfig( + lr_final=1e-4, max_steps=5000 + ), + }, + }, + viewer=ViewerConfig(num_rays_per_chunk=1 << 15), + vis="viewer", + ), + description="A larger version of LERF with a higher memory footprint, bigger CLIP model, and more hashgrid capacity", +) + +lerf_method_lite = MethodSpecification( + config=TrainerConfig( + method_name="lerf-lite", + steps_per_eval_batch=500, + steps_per_save=2000, + max_num_iterations=30000, + mixed_precision=True, + pipeline=LERFPipelineConfig( + datamanager=LERFDataManagerConfig( + dataparser=NerfstudioDataParserConfig(train_split_fraction=0.99), + train_num_rays_per_batch=4096, + eval_num_rays_per_batch=4096, + ), + model=LERFModelConfig( + eval_num_rays_per_chunk=1 << 15, + hashgrid_sizes=(19,), + hashgrid_layers=(16,), + hashgrid_resolutions=((16, 512),), + num_lerf_samples=12, + ), + network=OpenCLIPNetworkConfig( + clip_model_type="ViT-B-16", clip_model_pretrained="laion2b_s34b_b88k", clip_n_dims=512 + ), + ), + optimizers={ + "proposal_networks": { + "optimizer": AdamOptimizerConfig(lr=1e-2, eps=1e-15), + "scheduler": None, + }, + "fields": { + "optimizer": RAdamOptimizerConfig(lr=1e-2, eps=1e-15), + "scheduler": ExponentialDecaySchedulerConfig(lr_final=1e-3, max_steps=30000), + }, + "lerf": { + "optimizer": RAdamOptimizerConfig(lr=1e-2, eps=1e-15, weight_decay=1e-9), + "scheduler": ExponentialDecaySchedulerConfig(lr_final=1e-3, max_steps=7000), + }, + "camera_opt": { + "optimizer": AdamOptimizerConfig(lr=1e-3, eps=1e-15), + "scheduler": ExponentialDecaySchedulerConfig( + lr_final=1e-4, max_steps=5000 + ), + }, + }, + viewer=ViewerConfig(num_rays_per_chunk=1 << 15), + vis="viewer", + ), + description="A lightweight version of LERF designed to work on smaller GPUs", +) diff --git a/Extra-Methods-Patches/opennerf/opennerf/opennerf_datamanager.py b/Extra-Methods-Patches/opennerf/opennerf/opennerf_datamanager.py new file mode 100644 index 0000000000..d90788ff1e --- /dev/null +++ b/Extra-Methods-Patches/opennerf/opennerf/opennerf_datamanager.py @@ -0,0 +1,113 @@ +# Copyright 2022 The Nerfstudio Team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Datamanager. +""" + +from __future__ import annotations + +import os.path as osp +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Dict, List, Literal, Optional, Tuple, Type, Union + +import torch +from nerfstudio.cameras.rays import RayBundle +from rich.progress import Console + +CONSOLE = Console(width=120) + +from opennerf.data.utils.dino_dataloader import DinoDataloader +from opennerf.data.utils.openseg_dataloader import OpenSegDataloader +from nerfstudio.data.datamanagers.base_datamanager import VanillaDataManager, VanillaDataManagerConfig + + +@dataclass +class OpenNerfDataManagerConfig(VanillaDataManagerConfig): + _target: Type = field(default_factory=lambda: OpenNerfDataManager) + patch_tile_size_range: Tuple[float, float] = (0.05, 0.5) + patch_tile_size_res: int = 7 + patch_stride_scaler: float = 0.5 + + +class OpenNerfDataManager(VanillaDataManager): # pylint: disable=abstract-method + """Basic stored data manager implementation. + + This is pretty much a port over from our old dataloading utilities, and is a little jank + under the hood. We may clean this up a little bit under the hood with more standard dataloading + components that can be strung together, but it can be just used as a black box for now since + only the constructor is likely to change in the future, or maybe passing in step number to the + next_train and next_eval functions. + + Args: + config: the DataManagerConfig used to instantiate class + """ + + config: OpenNerfDataManagerConfig + + def __init__( + self, + config: OpenNerfDataManagerConfig, + device: Union[torch.device, str] = "cpu", + test_mode: Literal["test", "val", "inference"] = "val", + world_size: int = 1, + local_rank: int = 0, + **kwargs, # pylint: disable=unused-argument + ): + super().__init__( + config=config, device=device, test_mode=test_mode, world_size=world_size, local_rank=local_rank, **kwargs + ) + + if test_mode == 'inference': + return + + images = [self.train_dataset[i]["image"].permute(2, 0, 1)[None, ...] for i in range(len(self.train_dataset))] + images = torch.cat(images) + + cache_dir = f"outputs/{self.config.dataparser.data.parent.name}/{self.config.dataparser.data.name}" + dino_cache_path = Path(osp.join(cache_dir, "dino.npy")) + openseg_cache_path = Path(osp.join(cache_dir, "openseg.npy")) + # NOTE: cache config is sensitive to list vs. tuple, because it checks for dict equality + image_pathes = self.train_dataset._dataparser_outputs.image_filenames + + self.dino_dataloader = DinoDataloader( + image_list=images, + device=self.device, + cfg={"image_shape": list(images.shape[2:4])}, + cache_path=dino_cache_path, + ) + self.openseg_dataloader = OpenSegDataloader( + image_list=image_pathes, + device=self.device, + cfg={"image_shape": list(images.shape[2:4])}, + cache_path=openseg_cache_path, + ) + torch.cuda.empty_cache() + + def next_train(self, step: int) -> Tuple[RayBundle, Dict]: + """Returns the next batch of data from the train dataloader.""" + self.train_count += 1 + image_batch = next(self.iter_train_image_dataloader) + assert self.train_pixel_sampler is not None + batch = self.train_pixel_sampler.sample(image_batch) + ray_indices = batch["indices"] + ray_bundle = self.train_ray_generator(ray_indices) + batch["dino"] = self.dino_dataloader(ray_indices) + batch["openseg"] = self.openseg_dataloader(ray_indices) + ray_bundle.metadata["fx"] = self.train_dataset.cameras[0].fx.item() + ray_bundle.metadata["width"] = self.train_dataset.cameras[0].width.item() + ray_bundle.metadata["fy"] = self.train_dataset.cameras[0].fy.item() + ray_bundle.metadata["height"] = self.train_dataset.cameras[0].height.item() + return ray_bundle, batch diff --git a/Extra-Methods-Patches/opennerf/opennerf/opennerf_model.py b/Extra-Methods-Patches/opennerf/opennerf/opennerf_model.py new file mode 100644 index 0000000000..b21f2a679c --- /dev/null +++ b/Extra-Methods-Patches/opennerf/opennerf/opennerf_model.py @@ -0,0 +1,120 @@ +from dataclasses import dataclass, field +from typing import Dict, List, Tuple, Type, Literal + +import torch +from nerfstudio.cameras.rays import RayBundle, RaySamples +from nerfstudio.field_components.field_heads import FieldHeadNames +from nerfstudio.models.nerfacto import NerfactoModel, NerfactoModelConfig +from nerfstudio.viewer.server.viewer_elements import * +from torch.nn import Parameter + +from opennerf.opennerf_field import OpenNerfField +from opennerf.opennerf_fieldheadnames import OpenNerfFieldHeadNames +from opennerf.opennerf_renderers import CLIPRenderer, MeanRenderer + + +@dataclass +class OpenNerfModelConfig(NerfactoModelConfig): + _target: Type = field(default_factory=lambda: OpenNerfModel) + clip_loss_weight: float = 0.1 + dino_loss_weight: float = 0.0 + openseg_loss_weight: float = 1.0 + openseg_loss: Literal["Huber", "Cosine", "MSE"] = 'MSE' + n_scales: int = 30 + max_scale: float = 1.5 + """maximum scale used to compute relevancy with""" + num_opennerf_samples: int = 24 + hashgrid_layers: Tuple[int, ...] = (12, 12) + hashgrid_resolutions: Tuple[Tuple[int, int], ...] = ((16, 128), (128, 512)) + hashgrid_sizes: Tuple[int, ...] = (19, 19) + num_hidden_clip_layers: int = 1 + + +class OpenNerfModel(NerfactoModel): + config: OpenNerfModelConfig + + def populate_modules(self): + super().populate_modules() + + self.renderer_clip = CLIPRenderer() + self.renderer_mean = MeanRenderer() + + self.opennerf_field = OpenNerfField( + self.config.hashgrid_layers, + self.config.hashgrid_sizes, + self.config.hashgrid_resolutions, + self.config.num_hidden_clip_layers, + ) + + def get_outputs(self, ray_bundle: RayBundle): + ray_samples, weights_list, ray_samples_list = self.proposal_sampler(ray_bundle, density_fns=self.density_fns) + ray_samples_list.append(ray_samples) + + nerfacto_field_outputs, outputs, weights = self._get_outputs_nerfacto(ray_samples) + opennerf_weights, best_ids = torch.topk(weights, self.config.num_opennerf_samples, dim=-2, sorted=False) + + def gather_fn(tens): + return torch.gather(tens, -2, best_ids.expand(*best_ids.shape[:-1], tens.shape[-1])) + + dataclass_fn = lambda dc: dc._apply_fn_to_fields(gather_fn, dataclass_fn) + opennerf_samples: RaySamples = ray_samples._apply_fn_to_fields(gather_fn, dataclass_fn) + + weights_list.append(weights) + if self.training: + outputs["weights_list"] = weights_list + outputs["ray_samples_list"] = ray_samples_list + + opennerf_field_outputs = self.opennerf_field.get_outputs(opennerf_samples) + + outputs["dino"] = self.renderer_mean( + embeds=opennerf_field_outputs[OpenNerfFieldHeadNames.DINO], weights=opennerf_weights.detach() + ) + outputs["openseg"] = self.renderer_mean( + embeds=opennerf_field_outputs[OpenNerfFieldHeadNames.OPENSEG], weights=opennerf_weights.detach() + ) + + return outputs + + + def _get_outputs_nerfacto(self, ray_samples: RaySamples): + field_outputs = self.field(ray_samples, compute_normals=self.config.predict_normals) + weights = ray_samples.get_weights(field_outputs[FieldHeadNames.DENSITY]) + + FieldHeadNames.UNCERTAINTY + + rgb = self.renderer_rgb(rgb=field_outputs[FieldHeadNames.RGB], weights=weights) + depth = self.renderer_depth(weights=weights, ray_samples=ray_samples) + accumulation = self.renderer_accumulation(weights=weights) + + outputs = { + "rgb": rgb, + "accumulation": accumulation, + "depth": depth, + } + + return field_outputs, outputs, weights + + def get_loss_dict(self, outputs, batch, metrics_dict=None): + loss_dict = super().get_loss_dict(outputs, batch, metrics_dict) + if self.training: + unreduced_dino = self.config.dino_loss_weight * torch.nn.functional.mse_loss( + outputs["dino"], batch["dino"], reduction="none") + loss_dict["dino_loss"] = unreduced_dino.sum(dim=-1).nanmean() + + if self.config.openseg_loss == 'Huber': + unreduced_openseg = self.config.openseg_loss_weight * torch.nn.functional.huber_loss( + outputs["openseg"], batch["openseg"], delta=1.25, reduction="none") + elif self.config.openseg_loss == 'Cosine': + unreduced_openseg = self.config.openseg_loss_weight * (1.0 - torch.nn.functional.cosine_similarity( + outputs["openseg"], batch["openseg"])) + elif self.config.openseg_loss == 'MSE': + unreduced_openseg = self.config.openseg_loss_weight * torch.nn.functional.mse_loss( + outputs["openseg"], batch["openseg"], reduction="none") + + loss_dict["openseg_loss"] = unreduced_openseg.sum(dim=-1).nanmean() + return loss_dict + + def get_param_groups(self) -> Dict[str, List[Parameter]]: + param_groups = super().get_param_groups() + param_groups["opennerf"] = list(self.opennerf_field.parameters()) + return param_groups diff --git a/Extra-Methods-Patches/pynerf/pynerf/data/datamanagers/random_subset_datamanager.py b/Extra-Methods-Patches/pynerf/pynerf/data/datamanagers/random_subset_datamanager.py new file mode 100644 index 0000000000..05a866d02d --- /dev/null +++ b/Extra-Methods-Patches/pynerf/pynerf/data/datamanagers/random_subset_datamanager.py @@ -0,0 +1,352 @@ +import random +from dataclasses import dataclass, field +from functools import cached_property +from pathlib import Path +from typing import Dict, List, Optional, Tuple, Type, Union, Literal + +import torch +from nerfstudio.cameras.camera_optimizers import CameraOptimizerConfig +from nerfstudio.cameras.rays import RayBundle +from nerfstudio.data.datamanagers.base_datamanager import ( + DataManager, + DataManagerConfig, + AnnotatedDataParserUnion, +) +from nerfstudio.data.dataparsers.base_dataparser import DataparserOutputs +from nerfstudio.data.datasets.base_dataset import InputDataset +from nerfstudio.engine.optimizers import AdamOptimizerConfig +from nerfstudio.engine.schedulers import ExponentialDecaySchedulerConfig +from nerfstudio.model_components.ray_generators import RayGenerator +from nerfstudio.utils.comms import get_rank, get_world_size +from rich.console import Console +from torch.nn import Parameter +from torch.utils.data import DistributedSampler, DataLoader + +from pynerf.data.dataparsers.multicam_dataparser import MulticamDataParserConfig +from pynerf.data.datasets.image_metadata import ImageMetadata +from pynerf.data.datasets.random_subset_dataset import RandomSubsetDataset +from pynerf.data.weighted_fixed_indices_eval_loader import WeightedFixedIndicesEvalDataloader +from pynerf.pynerf_constants import ( + RGB, + WEIGHT, + TRAIN_INDEX, + DEPTH, + POSE_SCALE_FACTOR, + RAY_INDEX, + RENDER_LEVELS, +) + +CONSOLE = Console(width=120) + + +@dataclass +class RandomSubsetDataManagerConfig(DataManagerConfig): + _target: Type = field(default_factory=lambda: RandomSubsetDataManager) + """Target class to instantiate.""" + + dataparser: AnnotatedDataParserUnion = field(default_factory=MulticamDataParserConfig) + """Specifies the dataparser used to unpack the data.""" + + train_num_rays_per_batch: int = 4096 + """Number of rays per batch to use per training iteration.""" + + eval_num_rays_per_batch: int = 8192 + """Number of rays per batch to use per eval iteration.""" + + eval_image_indices: Optional[Tuple[int, ...]] = None + """Specifies the image indices to use during eval; if None, uses all val images.""" + + camera_optimizer: CameraOptimizerConfig = field( + default_factory=lambda: CameraOptimizerConfig( + optimizer=AdamOptimizerConfig(lr=6e-6, eps=1e-15), + scheduler=ExponentialDecaySchedulerConfig(lr_final=6e-4, max_steps=125000), + ) + ) + """Specifies the camera pose optimizer used during training. Helpful if poses are noisy, such as for data from + Record3D.""" + + items_per_chunk: int = 25600000 + """Number of entries to load into memory at a time""" + + local_cache_path: Optional[str] = "scratch/pynerf-cache" + """Caches images and metadata in specific path if set.""" + + on_demand_threads: int = 16 + """Number of threads to use when reading data""" + + load_all_in_memory: bool = False + """Load all of the dataset in memory vs sampling from disk""" + + patch_tile_size_range: Tuple[float, float] = (0.05, 0.5) + """ + Range for patch tile size ratios. + + IMPORTANT: + This must be float-based. Older code sometimes annotated this as Tuple[int, int] + while using a default like (0.05, 0.5), which breaks newer Tyro versions when + generating the CLI. + """ + + +class RandomSubsetDataManager(DataManager): + """Data manager implementation that samples batches of random pixels/rays/metadata in a chunked manner. + It can handle datasets that are larger than what can be held in memory + + Args: + config: the DataManagerConfig used to instantiate class + """ + + config: RandomSubsetDataManagerConfig + + train_dataset: InputDataset + """Used by the viewer and in various checks in the trainer, but is not actually used to sample batches""" + + def __init__( + self, + config: RandomSubsetDataManagerConfig, + device: Union[torch.device, str] = "cpu", + test_mode: Literal["test", "val", "inference"] = "test", + world_size: int = 1, + local_rank: int = 0, + ): + self.test_mode = test_mode # Needed for parent class + super().__init__() + + self.config = config + self.device = device + self.world_size = world_size + self.local_rank = local_rank + + if self.config.data is not None: + self.config.dataparser.data = Path(self.config.data) + else: + self.config.data = self.config.dataparser.data + + dataparser = self.config.dataparser.setup() + self.includes_time = dataparser.includes_time + self.train_dataparser_outputs: DataparserOutputs = dataparser.get_dataparser_outputs(split="train") + + self.train_camera_optimizer = self.config.camera_optimizer.setup( + num_cameras=self.train_dataparser_outputs.cameras.size, + device=self.device, + ) + self.train_ray_generator = RayGenerator( + self.train_dataparser_outputs.cameras.to(self.device), + self.train_camera_optimizer, + ) + + fields_to_load = {RGB} + for additional_field in {DEPTH, WEIGHT, TRAIN_INDEX}: + if additional_field in self.train_dataparser_outputs.metadata: + fields_to_load.add(additional_field) + + self.train_batch_dataset = RandomSubsetDataset( + items=self._get_image_metadata(self.train_dataparser_outputs), + fields_to_load=fields_to_load, + on_demand_threads=self.config.on_demand_threads, + items_per_chunk=self.config.items_per_chunk, + load_all_in_memory=self.config.load_all_in_memory, + ) + + self.iter_train_image_dataloader = iter([]) + self.train_dataset = InputDataset(self.train_dataparser_outputs) + + self.eval_dataparser_outputs = dataparser.get_dataparser_outputs(split="test") # test_mode + + self.eval_dataset = InputDataset(self.eval_dataparser_outputs) + self.eval_camera_optimizer = self.config.camera_optimizer.setup( + num_cameras=self.eval_dataparser_outputs.cameras.size, + device=self.device, + ) + self.eval_ray_generator = RayGenerator( + self.eval_dataparser_outputs.cameras.to(self.device), + self.eval_camera_optimizer, + ) + + self.eval_image_metadata = self._get_image_metadata(self.eval_dataparser_outputs) + self.eval_batch_dataset = RandomSubsetDataset( + items=self.eval_image_metadata, + fields_to_load=fields_to_load, + on_demand_threads=self.config.on_demand_threads, + items_per_chunk=(self.config.eval_num_rays_per_batch * 10), + load_all_in_memory=self.config.load_all_in_memory, + ) + + self.iter_eval_batch_dataloader = iter([]) + + @cached_property + def fixed_indices_eval_dataloader(self): + image_indices = [] + for item_index in range(get_rank(), len(self.eval_dataparser_outputs.cameras), get_world_size()): + image_indices.append(item_index) + + return WeightedFixedIndicesEvalDataloader( + input_dataset=self.eval_dataset, + device=self.device, + num_workers=self.world_size * 4, + image_indices=image_indices, + ) + + def _set_train_loader(self): + batch_size = self.config.train_num_rays_per_batch // max(self.world_size, 1) + + if self.world_size > 1: + self.train_sampler = DistributedSampler( + self.train_batch_dataset, + self.world_size, + self.local_rank, + ) + assert self.config.train_num_rays_per_batch % self.world_size == 0 + self.train_image_dataloader = DataLoader( + self.train_batch_dataset, + batch_size=batch_size, + sampler=self.train_sampler, + num_workers=0, + pin_memory=True, + ) + else: + self.train_image_dataloader = DataLoader( + self.train_batch_dataset, + batch_size=batch_size, + shuffle=True, + num_workers=0, + pin_memory=True, + ) + + self.iter_train_image_dataloader = iter(self.train_image_dataloader) + + def _set_eval_batch_loader(self): + batch_size = self.config.eval_num_rays_per_batch // max(self.world_size, 1) + + if self.world_size > 1: + self.eval_sampler = DistributedSampler( + self.eval_batch_dataset, + self.world_size, + self.local_rank, + ) + assert self.config.eval_num_rays_per_batch % self.world_size == 0 + self.eval_batch_dataloader = DataLoader( + self.eval_batch_dataset, + batch_size=batch_size, + sampler=self.eval_sampler, + num_workers=0, + pin_memory=True, + ) + else: + self.eval_batch_dataloader = DataLoader( + self.eval_batch_dataset, + batch_size=batch_size, + shuffle=True, + num_workers=0, + pin_memory=True, + ) + + self.iter_eval_batch_dataloader = iter(self.eval_batch_dataloader) + + def next_train(self, step: int) -> Tuple[RayBundle, Dict]: + """Returns the next batch of data from the train dataloader.""" + self.train_count += 1 + batch = next(self.iter_train_image_dataloader, None) + if batch is None: + self.train_batch_dataset.load_chunk() + self._set_train_loader() + batch = next(self.iter_train_image_dataloader) + + ray_bundle = self.train_ray_generator(batch[RAY_INDEX]) + self.transfer_train_index(ray_bundle, batch) + return ray_bundle, batch + + def next_eval(self, step: int) -> Tuple[RayBundle, Dict]: + """Returns the next batch of data from the eval dataloader.""" + self.eval_count += 1 + batch = next(self.iter_eval_batch_dataloader, None) + if batch is None: + self.eval_batch_dataset.load_chunk() + self._set_eval_batch_loader() + batch = next(self.iter_eval_batch_dataloader) + + ray_bundle = self.eval_ray_generator(batch[RAY_INDEX]) + self.transfer_train_index(ray_bundle, batch) + return ray_bundle, batch + + def next_eval_image(self, step: int) -> Tuple[int, RayBundle, Dict]: + image_index = random.choice(self.fixed_indices_eval_dataloader.image_indices) + ray_bundle, batch = self.fixed_indices_eval_dataloader.get_data_from_image_idx(image_index) + + metadata = self.eval_image_metadata[image_index] + + if ray_bundle.metadata is None: + ray_bundle.metadata = {} + ray_bundle.metadata[RENDER_LEVELS] = True + + if metadata.train_index is not None: + ray_bundle.metadata[TRAIN_INDEX] = torch.full_like( + ray_bundle.camera_indices, + metadata.train_index, + dtype=torch.int64, + ) + if metadata.weight is not None: + batch[WEIGHT] = torch.full_like( + ray_bundle.camera_indices, + metadata.weight, + dtype=torch.float32, + ) + + if metadata.depth_path is not None: + batch[DEPTH] = metadata.load_depth().to(ray_bundle.camera_indices.device).unsqueeze(-1) + + return image_index, ray_bundle, batch + + def get_train_rays_per_batch(self) -> int: + return self.config.train_num_rays_per_batch + + def get_eval_rays_per_batch(self) -> int: + return self.config.eval_num_rays_per_batch + + def get_datapath(self) -> Path: + return self.config.dataparser.data + + def get_param_groups(self) -> Dict[str, List[Parameter]]: + """Get the param groups for the data manager. + Returns: + A list of dictionaries containing the data manager's param groups. + """ + param_groups: Dict[str, List[Parameter]] = {} + + camera_opt_params = list(self.train_camera_optimizer.parameters()) + if self.config.camera_optimizer.mode != "off": + assert len(camera_opt_params) > 0 + param_groups[self.config.camera_optimizer.param_group] = camera_opt_params + else: + assert len(camera_opt_params) == 0 + + return param_groups + + def _get_image_metadata(self, outputs: DataparserOutputs) -> List[ImageMetadata]: + local_cache_path = Path(self.config.local_cache_path) if self.config.local_cache_path is not None else None + + items: List[ImageMetadata] = [] + for i in range(len(outputs.image_filenames)): + items.append( + ImageMetadata( + str(outputs.image_filenames[i]), + int(outputs.cameras.width[i]), + int(outputs.cameras.height[i]), + outputs.metadata[DEPTH][i] if DEPTH in outputs.metadata else None, + str(outputs.mask_filenames[i]) if outputs.mask_filenames is not None else None, + float(outputs.metadata[WEIGHT][i]) if WEIGHT in outputs.metadata else None, + int(outputs.metadata[TRAIN_INDEX][i]) if TRAIN_INDEX in outputs.metadata else None, + outputs.metadata[POSE_SCALE_FACTOR] if POSE_SCALE_FACTOR in outputs.metadata else 1, + local_cache_path, + ) + ) + + return items + + @staticmethod + def transfer_train_index(ray_bundle: RayBundle, batch: Dict) -> None: + if TRAIN_INDEX in batch: + if ray_bundle.metadata is None: + ray_bundle.metadata = {} + ray_bundle.metadata[TRAIN_INDEX] = batch[TRAIN_INDEX].unsqueeze(-1).to(ray_bundle.origins.device) + del batch[TRAIN_INDEX] \ No newline at end of file diff --git a/Extra-Methods-Patches/relationfield/relationfield/relationfield_model.py b/Extra-Methods-Patches/relationfield/relationfield/relationfield_model.py new file mode 100644 index 0000000000..2fb990ab20 --- /dev/null +++ b/Extra-Methods-Patches/relationfield/relationfield/relationfield_model.py @@ -0,0 +1,771 @@ +# Copyright (c) 2025 Robert Bosch GmbH +# SPDX-License-Identifier: AGPL-3.0 + +import os +from collections import defaultdict +from dataclasses import dataclass, field +from typing import Dict, List, Tuple, Type, Literal, Union + +from torch.nn import Parameter +import numpy as np +from torchtyping import TensorType +import torch +import torch.nn.functional as F +from nerfstudio.cameras.cameras import Cameras +from nerfstudio.cameras.rays import RayBundle, RaySamples, Frustums +from nerfstudio.field_components.field_heads import FieldHeadNames +from nerfstudio.models.nerfacto import NerfactoModel, NerfactoModelConfig +from nerfstudio.models.depth_nerfacto import DepthNerfactoModel, DepthNerfactoModelConfig + +from nerfstudio.viewer.viewer_elements import * +from nerfstudio.model_components.losses import scale_gradients_by_distance_squared +from nerfstudio.field_components.activations import trunc_exp + +from relationfield.instance_field import ( + GarField, + GarFieldConfig, +) +from relationfield.relationfield_renderers import MeanRenderer, FeatureRenderer +from relationfield.semantic_field import OpenNerfField, OpenNerfFieldHeadNames +from relationfield.relation_field import RelationField + + +if os.getenv("NERFACTO_DEPTH"): + MODEL = DepthNerfactoModel + CONFIG = DepthNerfactoModelConfig +else: + MODEL = NerfactoModel + CONFIG = NerfactoModelConfig + + + +@dataclass +class RelationFieldModelConfig(CONFIG): + _target: Type = field(default_factory=lambda: RelationFieldModel) + instance_field: GarFieldConfig = GarFieldConfig() + + max_grouping_scale: float = 2.0 + """Maximum scale to use for grouping supervision. Should be set during pipeline init.""" + + num_feat_samples: int = 24 + """Number of samples per ray to use for grouping supervision.""" + + use_hierarchy_losses: bool = True + use_single_scale: bool = False + """For ablation only. For full relationfield, keep hierarchy=True and single_scale=False.""" + + clip_loss_weight: float = 1.0 + openseg_loss_weight: float = 0.1 + instance_loss_weight: float = 1.0 + relation_loss_weight: float = 1.0 + relation_lambda_negatives: float = 0.05 + dynamic_relation_lambda: bool = False + relation_shared_enc: bool = False + relation_semantic_feat: bool = False + norm_feats: bool = False + relation_occurance_weight: bool = False + + openseg_loss: Literal["Huber", "Cosine", "MSE"] = 'MSE' + relation_loss: Literal["Huber", "Cosine", "MSE"] = 'MSE' + if openseg_loss == 'Cosine': + openseg_loss_weight*=0.01 + if relation_loss == 'Cosine': + relation_loss_weight*=0.01 + n_scales: int = 30 + max_scale: float = 1.5 + """maximum scale used to compute relevancy with""" + num_semantic_samples: int = 24 + hashgrid_layers: Tuple[int, ...] = (12, 12) + hashgrid_resolutions: Tuple[Tuple[int, int], ...] = ((16, 128), (128, 512)) + hashgrid_sizes: Tuple[int, ...] = (19, 19) + num_hidden_clip_layers: int = 1 + + +class RelationFieldModel(MODEL): + config: RelationFieldModelConfig + grouping_field: GarField + + def populate_modules(self): + super().populate_modules() + self.renderer_feat = FeatureRenderer() + self.renderer_mean = MeanRenderer() + + self.config.instance_field.use_single_scale = self.config.use_single_scale + + + # Add a slider to the viewer to control the scale of the grouping field. + self.scale_slider = ViewerSlider("Scale", 0.1, 0.0, 2.0, 0.001, visible=False) + self.thresh_slider = ViewerSlider("Threshold", 0.5, 0.0, 1.0, 0.001) + + # Store reference to click interface for relationfield. + # Note the List[RelationFieldModel] is to avoid circular children. + from relationfield.relationfield_interaction import RelationFieldClickScene + self.click_scene: RelationFieldClickScene = RelationFieldClickScene( + device=("cuda" if torch.cuda.is_available() else "cpu"), + scale_handle=self.scale_slider, + thresh_handle=self.thresh_slider, + model_handle=[self] + ) + + self.grouping_field = self.config.instance_field.setup() + + self.semantic_field = OpenNerfField( + self.config.hashgrid_layers, + self.config.hashgrid_sizes, + self.config.hashgrid_resolutions, + self.config.num_hidden_clip_layers, + ) + + self.relation_field = RelationField( + self.config.hashgrid_layers, + self.config.hashgrid_sizes, + self.config.hashgrid_resolutions, + 3 if not self.config.relation_shared_enc else 8, + self.config.relation_shared_enc, + self.config.relation_semantic_feat, + ) + + + def forward(self, ray_bundle: Union[RayBundle, Cameras], batch=None) -> Dict[str, Union[torch.Tensor, List]]: + """Run forward starting with a ray bundle. This outputs different things depending on the configuration + of the model and whether or not the batch is provided (whether or not we are training basically) + + Args: + ray_bundle: containing all the information needed to render that ray latents included + """ + if self.collider is not None: + ray_bundle = self.collider(ray_bundle) + if batch is not None and 'query_bundle' in batch: + batch['query_bundle'] = self.collider(batch['query_bundle']) + + return self.get_outputs(ray_bundle, batch) + + @torch.autocast('cuda') + def get_outputs(self, ray_bundle: RayBundle, batch=None) -> Dict[str, TensorType]: + if batch is not None and 'query_bundle' in batch: + # concatentate the query bundle with the ray bundle + new_metadata = ray_bundle.metadata.copy() + new_metadata['n_query_rays'] = batch['query_bundle'].metadata['n_query_rays'] + new_metadata['directions_norm'] = torch.cat([ray_bundle.metadata['directions_norm'], torch.ones((new_metadata['n_query_rays'],1)).to(self.device)], dim=0) + new_metadata['scale'] = torch.cat([ray_bundle.metadata['scale'], torch.ones(new_metadata['n_query_rays']).to(self.device)], dim=0) + ray_bundle = RayBundle(origins=torch.cat([ray_bundle.origins, batch['query_bundle'].origins], dim=0), + directions=torch.cat([ray_bundle.directions, batch['query_bundle'].directions], dim=0), + pixel_area=torch.cat([ray_bundle.pixel_area, batch['query_bundle'].pixel_area], dim=0), + nears=torch.cat([ray_bundle.nears, batch['query_bundle'].nears], dim=0), + fars=torch.cat([ray_bundle.fars, batch['query_bundle'].fars], dim=0), + camera_indices=torch.cat([ray_bundle.camera_indices, batch['query_bundle'].camera_indices], dim=0), + metadata=new_metadata + ) + + outputs = super().get_outputs(ray_bundle) + + if self.grouping_field.quantile_transformer is None: + # If scale statistics are not available, it's not possible to calculate grouping features. + return outputs + + # Recalculate ray samples and weights + # ... only if the model is in eval mode, where it should be no_grad(). + # If in training mode, `outputs` should already have calculated ray samples and weights. + # Without this if-block, camera optimizer? gradients? seem to get messed up. + ray_samples: RaySamples + if self.training: + ray_samples, weights = outputs["ray_samples_list"][-1], outputs["weights_list"][-1] + else: + ray_samples, weights_list, ray_samples_list = self.proposal_sampler(ray_bundle, density_fns=self.density_fns) + field_outputs = self.field.forward(ray_samples, compute_normals=self.config.predict_normals) + if self.config.use_gradient_scaling: + field_outputs = scale_gradients_by_distance_squared(field_outputs, ray_samples) + weights = ray_samples.get_weights(field_outputs[FieldHeadNames.DENSITY]) + + if batch is not None and 'query_bundle' in batch: + n_ray_bundle_rays = ray_samples.shape[0] - batch['query_bundle'].shape[0] + ray_samples, query_ray_samples = ray_samples[:n_ray_bundle_rays], ray_samples[n_ray_bundle_rays:] + weights, query_weights = weights[:n_ray_bundle_rays], weights[n_ray_bundle_rays:] + + # outputs_query = {} + for key in outputs.keys(): + if type(outputs[key]) is list: + # outputs_query[key] = [outputs[key][i][n_ray_bundle_rays:] for i in range(len(outputs[key]))] + outputs[key] = [outputs[key][i][:n_ray_bundle_rays] for i in range(len(outputs[key]))] + continue + # outputs_query[key] = outputs[key][n_ray_bundle_rays:] + outputs[key] = outputs[key][:n_ray_bundle_rays] + + # Choose the top k samples with the highest weights, to be used for grouping. + # This is to decrease # of samples queried for grouping, while sampling close to the scene density. + def gather_fn(tens): + return torch.gather( + tens, -2, best_ids.expand(*best_ids.shape[:-1], tens.shape[-1]) + ) + + dataclass_fn = lambda dc: dc._apply_fn_to_fields(gather_fn, dataclass_fn) + field_weights, best_ids = torch.topk( + weights, self.config.num_feat_samples, dim=-2, sorted=False + ) + field_samples: RaySamples = ray_samples._apply_fn_to_fields( + gather_fn, dataclass_fn + ) + if batch is not None and 'query_bundle' in batch: + def gather_fn_query(tens): + return torch.gather( + tens, -2, best_query_ids.expand(*best_query_ids.shape[:-1], tens.shape[-1]) + ) + dataclass_fn = lambda dc: dc._apply_fn_to_fields(gather_fn_query, dataclass_fn) + query_top_weights, best_query_ids = torch.topk( + query_weights, self.config.num_feat_samples, dim=-2, sorted=False + ) + query_samples: RaySamples = query_ray_samples._apply_fn_to_fields( + gather_fn_query, dataclass_fn + ) + + + # Define the scale for each sample. If the scale is not provided, use the selected scale. + # "scale" is included in ray_bundle.metadata only from training batches, but + # this would be good way to override the scale during inference. + if self.training and ("scale" in ray_bundle.metadata): + scales = ray_bundle.metadata["scale"] + if batch is not None and 'query_bundle' in batch: + scales = scales[0,:n_ray_bundle_rays] + instance_scales = scales.view(field_samples.shape[0], 1) + elif "scale" in ray_bundle.metadata: + if batch is not None and 'query_bundle' in batch: + scales = scales[0,:n_ray_bundle_rays] + scales = ray_bundle.metadata["scale"] + instance_scales = scales.view(field_samples.shape[0], 1) + else: + slider_value = self.scale_slider.value + instance_scales = ( + torch.ones(field_samples.shape[0], 1, device=self.device) + * slider_value + ) + + # Calculate features for the scale-conditioned grouping field. + # Hash values need to be included in the outputs for the loss calculation. + hash = self.grouping_field.get_hash(field_samples) + hash_rendered = self.renderer_feat( + embeds=hash, weights=field_weights.detach().half() + ) + + if self.training: + outputs["instance_hash"] = hash_rendered # normalized! + + outputs["instance"] = self.grouping_field.get_mlp(hash_rendered, instance_scales).float() + + semantic_field_outputs = self.semantic_field.get_outputs(field_samples) + outputs["openseg"] = self.renderer_mean( + embeds=semantic_field_outputs[OpenNerfFieldHeadNames.OPENSEG], weights=field_weights.detach() + ) + if self.training and batch is not None and 'query_bundle' in batch: + if not self.config.relation_shared_enc: + relation_feature = self.relation_embedding(field_samples, semantic_field_outputs[OpenNerfFieldHeadNames.OPENSEG], query_samples, mask=None) + else: + relation_feature = self.relation_embedding_shared_enc(field_samples, semantic_field_outputs[OpenNerfFieldHeadNames.OPENSEG], query_samples, mask=None) + + outputs["relation"] = self.renderer_mean(embeds=relation_feature, weights=field_weights.detach()) + + with torch.no_grad(): + # Interactive scene clicking + click_output = self.click_scene.get_outputs(outputs) + if click_output is not None: + outputs.update(click_output) + + relation_click_output = self.click_scene.get_relation_outputs(outputs, field_samples,semantic_field_outputs[OpenNerfFieldHeadNames.OPENSEG]) + if relation_click_output is not None: + relation_click_output['relation_map'] = self.renderer_mean(embeds=relation_click_output['relation'], weights=field_weights.detach()).float() + del relation_click_output['relation'] + outputs.update(relation_click_output) + + relavancy_rel_outputs = self.click_scene.get_max_across_relation(field_samples,outputs,field_weights) + if relavancy_rel_outputs is not None: + outputs.update(relavancy_rel_outputs) + outputs["rgb_rel_relevancy_raw"] = self.click_scene.overlay_activation_rgb(outputs["relation_relevancy_raw"],outputs["rgb"]) + outputs["rgb_rel_relevancy_scaled"] = self.click_scene.overlay_activation_rgb(outputs["relation_relevancy_scaled"],outputs["rgb"]) + + relavancy_outputs = self.click_scene.get_max_across(ray_samples,outputs) + if relavancy_outputs is not None: + outputs.update(relavancy_outputs) + outputs["rgb_relevancy"] = self.click_scene.overlay_activation_rgb(outputs["relevancy"],outputs["rgb"]) + + emb_click_output = self.click_scene.get_outputs_similarity(field_samples,outputs) + if emb_click_output is not None: + outputs.update(emb_click_output) + return outputs + + def _get_outputs_nerfacto(self, ray_samples: RaySamples): + field_outputs = self.field(ray_samples, compute_normals=self.config.predict_normals) + weights = ray_samples.get_weights(field_outputs[FieldHeadNames.DENSITY]) + + FieldHeadNames.UNCERTAINTY + + rgb = self.renderer_rgb(rgb=field_outputs[FieldHeadNames.RGB], weights=weights) + depth = self.renderer_depth(weights=weights, ray_samples=ray_samples) + accumulation = self.renderer_accumulation(weights=weights) + + outputs = { + "rgb": rgb, + "accumulation": accumulation, + "depth": depth, + } + + return field_outputs, outputs, weights + + @torch.no_grad() + def get_grouping_at_points(self, positions: TensorType, scale: float) -> TensorType: + """Get the grouping features at a set of points, given a scale.""" + # Apply distortion, calculate hash values, then normalize + positions = self.grouping_field.spatial_distortion(positions) + positions = (positions + 2.0) / 4.0 + xs = [e(positions.view(-1, 3)) for e in self.grouping_field.enc_list] + x = torch.concat(xs, dim=-1) + x = x / x.norm(dim=-1, keepdim=True) + + # Calculate grouping features; create a scale tensor to match the batch size + instance_scale = torch.ones((x.shape[0], 1), device=self.device) * scale + return self.grouping_field.get_mlp(x, instance_scale) + + + def relation_embedding(self, ray_samples: RaySamples, semantic_embeddings: torch.Tensor, query_samples: RaySamples, mask: torch.Tensor=None) -> torch.Tensor: + """Calculate the relation embedding between semantic embeddings and query positions.""" + # get semantic embeddings at query positions + if mask is None: + mask = torch.ones(semantic_embeddings.shape[0], dtype=torch.bool, device=self.device) + + query_pos = query_samples.frustums.get_positions().detach() + + query_pos = self.relation_field.spatial_distortion(query_pos) + query_pos = (query_pos + 2.0) / 4.0 + + positions = ray_samples.frustums.get_positions().detach()[mask] + positions = self.relation_field.spatial_distortion(positions) + positions = (positions + 2.0) / 4.0 + + if query_pos.shape[0] != positions.shape[0]: + query_pos = query_pos.repeat(positions.shape[0],1,1) + + xs = torch.concat([e(query_pos.view(-1, 3)) for e in self.semantic_field.clip_encs],dim=-1) + query_embd = self.semantic_field.openseg_net(xs) + + query_positions = torch.cat([e(query_pos.view(-1, 3)) for e in self.relation_field.encs],dim=-1) + + semantic_embd = semantic_embeddings[mask].view(-1,semantic_embeddings.shape[-1]) + field_positions = torch.concat([e(positions.view(-1, 3)) for e in self.relation_field.encs], dim=-1) + + if self.config.relation_semantic_feat: + relation_pre_embd = torch.cat(( + query_embd, # maybe not needed, cut for efficiency + query_positions, + semantic_embd, # maybe not needed, cut for efficiency + field_positions, + ), dim=-1) + else: + relation_pre_embd = torch.cat(( + query_positions, + field_positions, + ), dim=-1) + rel_feat = self.relation_field.relation_net(relation_pre_embd) + return rel_feat.view(*ray_samples[mask].shape, -1) + + def relation_embedding_from_points(self, ray_samples: torch.tensor, query_samples: torch.tensor, mask: torch.Tensor=None) -> torch.Tensor: + """Calculate the relation embedding between semantic embeddings and query positions.""" + # get semantic embeddings at query positions + if mask is None: + mask = torch.ones(ray_samples.shape[0], dtype=torch.bool, device=self.device) + + query_pos = query_samples.detach() + + query_pos = self.relation_field.spatial_distortion(query_pos) + query_pos = (query_pos + 2.0) / 4.0 + + positions = ray_samples.detach()[mask] + positions = self.relation_field.spatial_distortion(positions) + positions = (positions + 2.0) / 4.0 + + if query_pos.shape[0] != positions.shape[0]: + query_pos = query_pos.repeat(positions.shape[0],1,1) + + + query_positions = torch.cat([e(query_pos.view(-1, 3)) for e in self.relation_field.encs],dim=-1) + + field_positions = torch.concat([e(positions.view(-1, 3)) for e in self.relation_field.encs], dim=-1) + + + relation_pre_embd = torch.cat(( + query_positions, + field_positions, + ), dim=-1) + rel_feat = self.relation_field.relation_net(relation_pre_embd) + + return rel_feat.view(*ray_samples[mask].shape[:-1], -1) + + + def relation_embedding_shared_enc(self, ray_samples: RaySamples, semantic_embeddings: torch.Tensor, query_samples: RaySamples, mask: torch.Tensor=None) -> torch.Tensor: + """Calculate the relation embedding between semantic embeddings and query positions.""" + # get semantic embeddings at query positions + if mask is None: + mask = torch.ones(semantic_embeddings.shape[0], dtype=torch.bool, device=self.device) + + query_pos = query_samples.frustums.get_positions().detach() + query_pos = self.relation_field.spatial_distortion(query_pos) + query_pos = (query_pos + 2.0) / 4.0 + + positions = ray_samples.frustums.get_positions().detach()[mask] + positions = self.relation_field.spatial_distortion(positions) + positions = (positions + 2.0) / 4.0 + + if query_pos.shape[0] != positions.shape[0]: + query_pos = query_pos.repeat(positions.shape[0],1,1) + xs = torch.cat([e(torch.concat((positions.view(-1,3),query_pos.view(-1, 3)),dim=-1)) for e in self.relation_field.encs],dim=-1) + + rel_feat = self.relation_field.relation_net(xs) + return rel_feat.view(*ray_samples[mask].shape, -1) + + + + def get_loss_dict_group(self, outputs, batch, metrics_dict=None): + # loss_dict = super().get_loss_dict(outputs, batch, metrics_dict) + if not self.training: + return + + loss_dict = {} + margin = 1.0 + + #################################################################################### + # Calculate GT labels for the positive and negative pairs + #################################################################################### + # TODO(cmk) want to make this a little more efficient and cleaner + input_id1 = input_id2 = batch["mask_id"] + + # Expand labels + labels1_expanded = input_id1.unsqueeze(1).expand(-1, input_id1.shape[0]) + labels2_expanded = input_id2.unsqueeze(0).expand(input_id2.shape[0], -1) + + # Mask for positive/negative pairs across the entire matrix + mask_full_positive = labels1_expanded == labels2_expanded + mask_full_negative = ~mask_full_positive + + # Create a block mask to only consider pairs within the same image -- no cross-image pairs + chunk_size = batch["nPxImg"] # i.e., the number of rays per image + num_chunks = input_id1.shape[0] // chunk_size # i.e., # of images in the batch + block_mask = torch.kron( + torch.eye(num_chunks, device=self.device, dtype=bool), + torch.ones((chunk_size, chunk_size), device=self.device, dtype=bool), + ) # block-diagonal matrix, to consider only pairs within the same image + + # Only consider upper triangle to avoid double-counting + block_mask = torch.triu(block_mask, diagonal=0) + # Only consider pairs where both points are valid (-1 means not in mask / invalid) + block_mask = block_mask * (labels1_expanded != -1) * (labels2_expanded != -1) + + # Mask for diagonal elements (i.e., pairs of the same point). + # Don't consider these pairs for grouping supervision (pulling), since they are trivially similar. + diag_mask = torch.eye(block_mask.shape[0], device=self.device, dtype=bool) + + hash_rendered = outputs["instance_hash"] + scale = batch["scale"].view(-1, 1) + + #################################################################################### + # Grouping supervision + #################################################################################### + total_loss = 0 + + # 1. If (A, s_A) and (A', s_A) in same group, then supervise the features to be similar + # Note that `use_single_scale` (for ablation only) causes grouping_field to ignore the scale input. + instance = self.grouping_field.get_mlp(hash_rendered, scale) + mask = torch.where(mask_full_positive * block_mask * (~diag_mask)) + instance_loss_1 = torch.norm( + instance[mask[0]] - instance[mask[1]], p=2, dim=-1 + ).nansum() + total_loss += instance_loss_1 + + # 2. If ", then also supervise them to be similar at s > s_A + if self.config.use_hierarchy_losses and (not self.config.use_single_scale): + scale_diff = torch.max( + torch.zeros_like(scale), (self.config.max_grouping_scale - scale) + ) + larger_scale = scale + scale_diff * torch.rand( + size=(1,), device=scale.device + ) + instance = self.grouping_field.get_mlp(hash_rendered, larger_scale) + mask = torch.where(mask_full_positive * block_mask * (~diag_mask)) + instance_loss_2 = torch.norm( + instance[mask[0]] - instance[mask[1]], p=2, dim=-1 + ).nansum() + total_loss += instance_loss_2 + + # 4. Also supervising A, B to be dissimilar at scales s_A, s_B respectively seems to help. + instance = self.grouping_field.get_mlp(hash_rendered, scale) + mask = torch.where(mask_full_negative * block_mask) + instance_loss_4 = ( + F.relu( + margin - torch.norm(instance[mask[0]] - instance[mask[1]], p=2, dim=-1) + ) + ).nansum() + total_loss += instance_loss_4 + + loss_dict["instance_loss"] = self.config.instance_loss_weight *(total_loss / torch.sum(block_mask).float()) + + if self.config.instance_loss_weight == 0.0: + del loss_dict["instance_loss"] + + return loss_dict + + def get_loss_dict_segmentation(self, outputs, batch, metrics_dict=None): + if self.config.norm_feats: + outputs["openseg"] = F.normalize(outputs["openseg"], dim=-1) + outputs["clip"] = F.normalize(outputs["clip"], dim=-1) + loss_dict = {} + if self.training: + + if self.config.openseg_loss == 'Huber': + unreduced_openseg = self.config.openseg_loss_weight * torch.nn.functional.huber_loss( + outputs["openseg"], batch["openseg"], delta=1.25, reduction="none") + elif self.config.openseg_loss == 'Cosine': + unreduced_openseg = self.config.openseg_loss_weight * (1.0 - torch.nn.functional.cosine_similarity( + outputs["openseg"], batch["openseg"])) + elif self.config.openseg_loss == 'MSE': + unreduced_openseg = self.config.openseg_loss_weight * torch.nn.functional.mse_loss( + outputs["openseg"], batch["openseg"], reduction="none") + + #manually clip gradients + unreduced_openseg = torch.clamp(unreduced_openseg, -10.0, 10.0) + loss_dict["openseg_loss"] = unreduced_openseg.nansum(dim=-1).nanmean() + + if self.config.openseg_loss_weight == 0.0: + del loss_dict["openseg_loss"] + + return loss_dict + + + def get_loss_dict_relation(self, outputs, batch, metrics_dict=None): + if self.config.norm_feats: + outputs["relation"] = F.normalize(outputs["relation"], dim=-1) + + mask = batch["query_mask"] + loss_dict = {} + if self.training: + + if self.config.relation_loss == 'Huber': + unreduced_relation = self.config.relation_loss_weight * torch.nn.functional.huber_loss( + outputs["relation"], batch["relation_embd"], delta=1.25, reduction="none") + elif self.config.relation_loss == 'Cosine': + unreduced_relation = self.config.relation_loss_weight * (1.0 - torch.nn.functional.cosine_similarity( + outputs["relation"], batch["relation_embd"])) + elif self.config.relation_loss == 'MSE': + unreduced_relation = self.config.relation_loss_weight * torch.nn.functional.mse_loss( + outputs["relation"], batch["relation_embd"], reduction="none") + + #manually clip gradiants + unreduced_relation = torch.clamp(unreduced_relation, -10.0, 10.0) + + + # balance none relationships with semantic relationships + relation_lambda = mask.sum() / (~mask).sum() if self.config.dynamic_relation_lambda else self.config.relation_lambda_negatives + unreduced_relation[~mask] = relation_lambda*unreduced_relation[~mask] + + if self.config.relation_occurance_weight: + unreduced_relation = batch["rel_weight"].unsqueeze(1) * unreduced_relation + + loss_dict["relation_loss"] = unreduced_relation.nansum(dim=-1).nanmean() + + if self.config.relation_loss_weight == 0.0: + del loss_dict["relation_loss"] + + return loss_dict + + def get_param_groups(self) -> Dict[str, List[Parameter]]: + param_groups = super().get_param_groups() + param_groups["relationfield"] = list(self.grouping_field.parameters()) + list(self.semantic_field.parameters()) + list(self.relation_field.parameters()) + return param_groups + + def concatenate_ray_samples(self, ray_samples1: RaySamples, ray_samples2: RaySamples) -> RaySamples: + # Concatenate Frustums + frustums1, frustums2 = ray_samples1.frustums, ray_samples2.frustums + concatenated_frustums = Frustums( + origins=torch.cat([frustums1.origins, frustums2.origins], dim=0), + directions=torch.cat([frustums1.directions, frustums2.directions], dim=0), + starts=torch.cat([frustums1.starts, frustums2.starts], dim=0), + ends=torch.cat([frustums1.ends, frustums2.ends], dim=0), + pixel_area=torch.cat([frustums1.pixel_area, frustums2.pixel_area], dim=0), + offsets=torch.cat([frustums1.offsets, frustums2.offsets], dim=0) if frustums1.offsets is not None and frustums2.offsets is not None else None + ) + + # Concatenate other optional tensors + camera_indices = torch.cat([ray_samples1.camera_indices, ray_samples2.camera_indices], dim=0) if ray_samples1.camera_indices is not None and ray_samples2.camera_indices is not None else None + deltas = torch.cat([ray_samples1.deltas, ray_samples2.deltas], dim=0) if ray_samples1.deltas is not None and ray_samples2.deltas is not None else None + spacing_starts = torch.cat([ray_samples1.spacing_starts, ray_samples2.spacing_starts], dim=0) if ray_samples1.spacing_starts is not None and ray_samples2.spacing_starts is not None else None + spacing_ends = torch.cat([ray_samples1.spacing_ends, ray_samples2.spacing_ends], dim=0) if ray_samples1.spacing_ends is not None and ray_samples2.spacing_ends is not None else None + metadata = {key: torch.cat([ray_samples1.metadata[key], ray_samples2.metadata[key]], dim=0) if type(ray_samples1.metadata[key])==torch.Tensor else ray_samples1.metadata[key] for key in ray_samples1.metadata} + times = torch.cat([ray_samples1.times, ray_samples2.times], dim=0) if ray_samples1.times is not None and ray_samples2.times is not None else None + + # Create a new RaySamples object + concatenated_ray_samples = RaySamples( + frustums=concatenated_frustums, + camera_indices=camera_indices, + deltas=deltas, + spacing_starts=spacing_starts, + spacing_ends=spacing_ends, + spacing_to_euclidean_fn=ray_samples1.spacing_to_euclidean_fn, # assuming these are the same for both + metadata=metadata, + times=times + ) + + return concatenated_ray_samples + + @torch.no_grad() + def get_outputs_for_camera_ray_bundle(self, camera_ray_bundle: RayBundle) -> Dict[str, torch.Tensor]: + """Takes in camera parameters and computes the output of the model. + This is the same as the base model's, but with a try/except in the case the shape is incorrect. + + Args: + camera_ray_bundle: ray bundle to calculate outputs over + """ + input_device = camera_ray_bundle.directions.device + num_rays_per_chunk = self.config.eval_num_rays_per_chunk + image_height, image_width = camera_ray_bundle.origins.shape[:2] + num_rays = len(camera_ray_bundle) + outputs_lists = defaultdict(list) + for i in range(0, num_rays, num_rays_per_chunk): + start_idx = i + end_idx = i + num_rays_per_chunk + ray_bundle = camera_ray_bundle.get_row_major_sliced_ray_bundle(start_idx, end_idx) + # move the chunk inputs to the model device + ray_bundle = ray_bundle.to(self.device) + outputs = self.forward(ray_bundle=ray_bundle, batch=None) + for output_name, output in outputs.items(): # type: ignore + if not isinstance(output, torch.Tensor): + # TODO: handle lists of tensors as well + continue + # move the chunk outputs from the model device back to the device of the inputs. + outputs_lists[output_name].append(output.to(input_device)) + outputs = {} + for output_name, outputs_list in outputs_lists.items(): + if "field" in output_name: + N, S, D = outputs_list[0].shape + outputs[output_name] = torch.cat(outputs_list,dim=0).view(image_height, image_width, S, D) + else: + try: + outputs[output_name] = torch.cat(outputs_list).view(image_height, image_width, -1) # type: ignore + except: + pass + return outputs + + + @torch.no_grad() + def get_outputs_for_points(self, points_batch, scale=0.5) -> Dict[str, torch.Tensor]: + + query_pos = torch.from_numpy(points_batch).cuda() + query_pos_dist= self.semantic_field.spatial_distortion(query_pos) + query_pos_norm = (query_pos_dist+2.)/4. + + + h = self.field.mlp_base(query_pos_norm.view(-1, 3)) + density_before_activation, base_mlp_out = torch.split(h, [1, self.field.geo_feat_dim], dim=-1) + density = self.field.average_init_density * trunc_exp(density_before_activation.to('cuda')) + + xs = [e(query_pos_norm.view(-1, 3)) for e in self.semantic_field.clip_encs] + x = torch.concat(xs, dim=-1) + + clip_pass = self.semantic_field.clip_net(x) + clip_pass = clip_pass / torch.linalg.norm(clip_pass,dim=-1,keepdim=True) + + openseg_pass = self.semantic_field.openseg_net(x) + openseg_pass = openseg_pass / torch.linalg.norm(openseg_pass,dim=-1,keepdim=True) + + xs = [e(query_pos_norm.view(-1, 3)) for e in self.grouping_field.enc_list] + x = torch.concat(xs, dim=-1) + + x = x / x.norm(dim=-1, keepdim=True) + instance_scale = torch.ones((x.shape[0], 1), device=x.device) * scale + instance_pass = self.grouping_field.get_mlp(x, instance_scale.to(x.device)) + + return { + "clip": clip_pass.view(*points_batch.shape[:2], -1), + "openseg": openseg_pass.view(*points_batch.shape[:2], -1), + "instance": instance_pass.view(*points_batch.shape[:2], -1), + "density": density.view(*points_batch.shape[:2], -1) + } + + @torch.no_grad() + def get_outputs_for_points_with_query(self, points_batch, query, scale=0.5) -> Dict[str, torch.Tensor]: + """ + get point features for a given query point + """ + # add spatial distortion + position_pos = torch.from_numpy(points_batch).cuda() + position_pos_dist = self.semantic_field.spatial_distortion(position_pos) + position_pos_norm = (position_pos_dist+2.)/4. + # add spatial distortion to query point + query_pos = torch.from_numpy(query).cuda() + query_pos = query.unsqueeze(0).repeat(query_pos.shape[0],1) + query_pos_dist = self.relation_field.spatial_distortion(query_pos) + query_pos_norm = (query_pos_dist+2.)/4. + + semantic_dict = self.get_outputs_for_points(position_pos, None, None, scale) + + # compute relation features + field_positions = torch.concat([e(position_pos_norm.view(-1, 3)) for e in self.relation_field.encs], dim=-1) + query_positions = torch.concat([e(query_pos_norm.view(-1, 3)) for e in self.relation_field.encs], dim=-1) + relation_pre_embd = torch.cat(( + query_positions, + field_positions + ), dim=-1) + rel_feat = self.relation_field.relation_net(relation_pre_embd) + + semantic_dict["relation"] = rel_feat.view(*position_pos.shape[:2], -1) + return semantic_dict + + @torch.no_grad() + def get_outputs_for_points_with_query_batch(self, points_batch, query_batch, points_sem_emb=None, query_sem_emb=None) -> Dict[str, torch.Tensor]: + """ + get point features for given query points, + points_batch: [N,3] numpy array + query_batch: [K,3] numpy array + """ + # map both points and query points to the same shape [N,K,3] + N, K = points_batch.shape[0], query_batch.shape[0] + points_batch = np.expand_dims(points_batch, axis=1) + query_batch = np.expand_dims(query_batch, axis=0) + points_batch = np.repeat(points_batch, query_batch.shape[1], axis=1) + query_batch = np.repeat(query_batch, points_batch.shape[0], axis=0) + # now flatten both points and query points + points_batch = points_batch.reshape(-1,3) + query_batch = query_batch.reshape(-1,3) + + # add spatial distortion + position_pos = torch.from_numpy(points_batch).cuda() + position_pos_dist = self.relation_field.spatial_distortion(position_pos) + position_pos_norm = (position_pos_dist+2.)/4. + # add spatial distortion to query point + query = query_batch + query_pos = torch.from_numpy(query).cuda() + query_pos_dist = self.relation_field.spatial_distortion(query_pos) + query_pos_norm = (query_pos_dist+2.)/4. + + # compute relation features + field_positions = torch.concat([e(position_pos_norm.view(-1, 3)) for e in self.relation_field.encs], dim=-1) + query_positions = torch.concat([e(query_pos_norm.view(-1, 3)) for e in self.relation_field.encs], dim=-1) + + if points_sem_emb is not None and query_sem_emb is not None: + relation_pre_embd = torch.cat(( + query_sem_emb, + query_positions, + points_sem_emb, + field_positions + ), dim=-1) + else: + relation_pre_embd = torch.cat(( + query_positions, + field_positions + ), dim=-1) + rel_feat = self.relation_field.relation_net(relation_pre_embd) + + # rel_feat is of shape [N*K, 512], now reshape again to [N,K,512] + rel_feat = rel_feat.view(N,K,-1) + # now lets accumulate features across query points using mean + rel_feat = rel_feat.mean(dim=1) + + return { + "relation": rel_feat + } + + diff --git a/Extra-Methods-Patches/splatfacto-w/splatfactow/export_script.py b/Extra-Methods-Patches/splatfacto-w/splatfactow/export_script.py new file mode 100644 index 0000000000..3f6023d9dd --- /dev/null +++ b/Extra-Methods-Patches/splatfacto-w/splatfactow/export_script.py @@ -0,0 +1,236 @@ +# Copyright 2022 the Regents of the University of California, Nerfstudio Team and contributors. +# Licensed under the Apache License, Version 2.0. + +"""Export Splatfacto-W checkpoints to PLY. + +Retro-compatible patched exporter: +- prefers model.get_sh_coeffs(camera_idx=...) when present, +- falls back to model.color_nn.get_sh_coeffs(...) for forward-looking models, +- falls back again to legacy model.shs_0 / model.shs_rest if needed, +- keeps finite-value filtering before writing the PLY. +""" + +from __future__ import annotations + +import argparse +import typing +from collections import OrderedDict +from dataclasses import dataclass +from pathlib import Path +from typing import Optional, Tuple + +import numpy as np +import torch + +from nerfstudio.data.scene_box import OrientedBox +from nerfstudio.utils.eval_utils import eval_setup +from nerfstudio.utils.rich_utils import CONSOLE +from splatfactow.splatfactow_model import SplatfactoWModel + + +@dataclass +class Exporter: + load_config: Path + output_dir: Path + + +@dataclass +class ExportGaussianSplat(Exporter): + obb_center: Optional[Tuple[float, float, float]] = None + obb_rotation: Optional[Tuple[float, float, float]] = None + obb_scale: Optional[Tuple[float, float, float]] = None + camera_idx: Optional[int] = None + + @staticmethod + def write_ply(filename: str, count: int, map_to_tensors: typing.OrderedDict[str, np.ndarray]) -> None: + if not all(len(tensor) == count for tensor in map_to_tensors.values()): + raise ValueError("Count does not match the length of all tensors") + if not all( + isinstance(tensor, np.ndarray) + and (tensor.dtype.kind == "f" or tensor.dtype == np.uint8) + and tensor.size > 0 + for tensor in map_to_tensors.values() + ): + raise ValueError("All tensors must be non-empty numpy arrays of float or uint8 type") + + with open(filename, "wb") as ply_file: + ply_file.write(b"ply\n") + ply_file.write(b"format binary_little_endian 1.0\n") + ply_file.write(f"element vertex {count}\n".encode()) + for key, tensor in map_to_tensors.items(): + data_type = "float" if tensor.dtype.kind == "f" else "uchar" + ply_file.write(f"property {data_type} {key}\n".encode()) + ply_file.write(b"end_header\n") + for i in range(count): + for tensor in map_to_tensors.values(): + value = tensor[i] + if tensor.dtype.kind == "f": + ply_file.write(np.float32(value).tobytes()) + else: + ply_file.write(value.tobytes()) + + @staticmethod + def _appearance_embedding_for_export(model: SplatfactoWModel, camera_idx: Optional[int]) -> torch.Tensor: + if camera_idx is None: + if getattr(model.config, "use_avg_appearance", False): + return model.appearance_embeds.weight.mean(dim=0) + return model.appearance_embeds.weight[0] + if camera_idx < 0 or camera_idx >= model.num_train_data: + raise ValueError(f"camera_idx {camera_idx} is out of range [0, {model.num_train_data})") + return model.appearance_embeds(torch.tensor(camera_idx, device=model.device)) + + @staticmethod + def _normalize_sh_output(sh_coeffs: torch.Tensor) -> tuple[np.ndarray, np.ndarray]: + """Normalize SH coeff output to exporter layout.""" + if sh_coeffs.ndim != 3 or sh_coeffs.shape[-1] != 3: + raise ValueError(f"Unexpected SH coeff shape: {tuple(sh_coeffs.shape)}") + sh_coeffs = sh_coeffs.contiguous() + shs_0 = sh_coeffs[:, 0, :].detach().cpu().numpy() # [N, 3] + shs_rest = sh_coeffs[:, 1:, :].transpose(1, 2).contiguous().detach().cpu().numpy() # [N, 3, K-1] + shs_rest = shs_rest.reshape(shs_rest.shape[0], -1) + return shs_0, shs_rest + + @classmethod + def _export_sh_coeffs(cls, model: SplatfactoWModel, appearance_embed: torch.Tensor, camera_idx: Optional[int]) -> tuple[np.ndarray, np.ndarray]: + # Preferred modern API on the model itself. + if hasattr(model, "get_sh_coeffs") and callable(getattr(model, "get_sh_coeffs")): + with torch.no_grad(): + sh_coeffs = model.get_sh_coeffs(cam_idx=camera_idx) + return cls._normalize_sh_output(sh_coeffs) + + # Forward-looking field-based API. + color_nn = getattr(model, "color_nn", None) + appearance_features = getattr(model, "appearance_features", None) + if color_nn is not None and hasattr(color_nn, "get_sh_coeffs") and appearance_features is not None: + with torch.no_grad(): + sh_coeffs = color_nn.get_sh_coeffs( + appearance_embed=appearance_embed, + appearance_features=appearance_features, + num_sh=model.config.sh_degree, + ) + return cls._normalize_sh_output(sh_coeffs) + + # Legacy fallback using model.shs_0 / model.shs_rest properties. + if hasattr(model, "set_camera_idx") and camera_idx is not None: + try: + model.set_camera_idx(camera_idx) + except Exception: + pass + + if hasattr(model, "shs_0") and hasattr(model, "shs_rest"): + with torch.no_grad(): + shs_0_t = model.shs_0 + shs_rest_t = model.shs_rest + if shs_0_t.ndim == 3 and shs_0_t.shape[1] == 1: + shs_0 = shs_0_t.squeeze(1).detach().cpu().numpy() + elif shs_0_t.ndim == 2: + shs_0 = shs_0_t.detach().cpu().numpy() + else: + raise ValueError(f"Unexpected legacy shs_0 shape: {tuple(shs_0_t.shape)}") + + if shs_rest_t.ndim != 3: + raise ValueError(f"Unexpected legacy shs_rest shape: {tuple(shs_rest_t.shape)}") + shs_rest = shs_rest_t.transpose(1, 2).contiguous().detach().cpu().numpy() + shs_rest = shs_rest.reshape(shs_rest.shape[0], -1) + return shs_0, shs_rest + + raise AttributeError( + "Could not export SH coefficients: expected one of " + "model.get_sh_coeffs(...), model.color_nn.get_sh_coeffs(...), " + "or legacy model.shs_0 / model.shs_rest." + ) + + def main(self) -> None: + self.output_dir.mkdir(parents=True, exist_ok=True) + _, pipeline, _, _ = eval_setup(self.load_config) + model = pipeline.model + + # Accept any splatfacto-like model (including your custom one) + if not hasattr(model, "means") or not hasattr(model, "scales"): + raise TypeError(f"Model {type(model).__name__} is not splatfacto-compatible") + + model: SplatfactoWModel = pipeline.model + filename = self.output_dir / "splat.ply" + map_to_tensors: "OrderedDict[str, np.ndarray]" = OrderedDict() + + with torch.no_grad(): + appearance_embed = self._appearance_embedding_for_export(model, self.camera_idx) + positions = model.means.detach().cpu().numpy() + count = positions.shape[0] + n = count + + map_to_tensors["x"] = positions[:, 0] + map_to_tensors["y"] = positions[:, 1] + map_to_tensors["z"] = positions[:, 2] + map_to_tensors["nx"] = np.zeros(n, dtype=np.float32) + map_to_tensors["ny"] = np.zeros(n, dtype=np.float32) + map_to_tensors["nz"] = np.zeros(n, dtype=np.float32) + + if model.config.sh_degree <= 0: + raise ValueError("SH degree must be greater than 0 for Gaussian export") + + shs_0, shs_rest = self._export_sh_coeffs(model, appearance_embed, self.camera_idx) + for i in range(shs_0.shape[1]): + map_to_tensors[f"f_dc_{i}"] = shs_0[:, i] + for i in range(shs_rest.shape[1]): + map_to_tensors[f"f_rest_{i}"] = shs_rest[:, i] + + map_to_tensors["opacity"] = model.opacities.detach().cpu().numpy().reshape(-1) + scales = model.scales.detach().cpu().numpy() + for i in range(3): + map_to_tensors[f"scale_{i}"] = scales[:, i] + quats = model.quats.detach().cpu().numpy() + for i in range(4): + map_to_tensors[f"rot_{i}"] = quats[:, i] + + if self.obb_center is not None and self.obb_rotation is not None and self.obb_scale is not None: + crop_obb = OrientedBox.from_params(self.obb_center, self.obb_rotation, self.obb_scale) + if crop_obb is None: + raise ValueError("Failed to construct crop OBB") + mask = crop_obb.within(torch.from_numpy(positions)).cpu().numpy() + for key in list(map_to_tensors.keys()): + map_to_tensors[key] = map_to_tensors[key][mask] + count = int(mask.sum()) + + select = np.ones(count, dtype=bool) + for key, tensor in map_to_tensors.items(): + tensor_2d = tensor if tensor.ndim > 1 else tensor[:, None] + before = int(np.sum(select)) + select = np.logical_and(select, np.isfinite(tensor_2d).all(axis=-1)) + after = int(np.sum(select)) + if after < before: + CONSOLE.print(f"{before - after} NaN/Inf elements in {key}") + + if int(np.sum(select)) < count: + CONSOLE.print(f"values have NaN/Inf in map_to_tensors, only export {int(np.sum(select))}/{count}") + for key in list(map_to_tensors.keys()): + map_to_tensors[key] = map_to_tensors[key][select] + count = int(np.sum(select)) + + self.write_ply(str(filename), count, map_to_tensors) + CONSOLE.print(f"Exported {count} gaussians to {filename}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Export a Gaussian Splat model to a .ply") + parser.add_argument("--load_config", type=Path, help="Path to the config YAML file.") + parser.add_argument("--output_dir", type=Path, help="Path to the output directory.") + parser.add_argument("--obb_center", type=str, help="Center of the oriented bounding box.") + parser.add_argument("--obb_rotation", type=str, help="Rotation of the oriented bounding box in RPY radians.") + parser.add_argument("--obb_scale", type=str, help="Scale of the oriented bounding box along each axis.") + parser.add_argument("--camera_idx", type=int, help="Camera index to use for export appearance.") + args = parser.parse_args() + + obb_center = tuple(map(float, args.obb_center.split(","))) if args.obb_center else None + obb_rotation = tuple(map(float, args.obb_rotation.split(","))) if args.obb_rotation else None + obb_scale = tuple(map(float, args.obb_scale.split(","))) if args.obb_scale else None + + exporter = ExportGaussianSplat( + load_config=args.load_config, + output_dir=args.output_dir, + obb_center=obb_center, + obb_rotation=obb_rotation, + obb_scale=obb_scale, + camera_idx=args.camera_idx, + ) + exporter.main() diff --git a/Extra-Methods-Patches/splatfacto-w/splatfactow/nerfw_dataparser.py b/Extra-Methods-Patches/splatfacto-w/splatfactow/nerfw_dataparser.py new file mode 100644 index 0000000000..9fff1f0a5b --- /dev/null +++ b/Extra-Methods-Patches/splatfacto-w/splatfactow/nerfw_dataparser.py @@ -0,0 +1,262 @@ +# Copyright 2022 the Regents of the University of California, Nerfstudio Team and contributors. +# Licensed under the Apache License, Version 2.0. + +"""Phototourism / NeRF-W dataset parser for Splatfacto-W. + +This version keeps the original training behavior but fixes a few structural issues: +- consistently uses config.colmap_path, +- iterates COLMAP images correctly (image ids != camera ids), +- validates TSV split files more carefully, +- keeps a stable mapping from eval-dataset indices to original image indices. +""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from pathlib import Path +from typing import Literal, Optional, Type + +import numpy as np +import pandas as pd +import torch + +from nerfstudio.cameras import camera_utils +from nerfstudio.cameras.cameras import Cameras, CameraType +from nerfstudio.data.dataparsers.base_dataparser import DataParser, DataParserConfig, DataparserOutputs +from nerfstudio.data.scene_box import SceneBox +from nerfstudio.data.utils import colmap_parsing_utils as colmap_utils +from nerfstudio.plugins.registry_dataparser import DataParserSpecification +from nerfstudio.utils.rich_utils import CONSOLE + + +@dataclass +class NerfWDataParserConfig(DataParserConfig): + _target: Type = field(default_factory=lambda: NerfW) + data: Path = Path("data/brandenburg-gate") + data_name: Literal["brandenburg", "trevi", "sacre"] = "brandenburg" + scale_factor: float = 3.0 + alpha_color: str = "white" + scene_scale: float = 1.0 + orientation_method: Literal["pca", "up", "vertical", "none"] = "up" + center_method: Literal["poses", "focus", "none"] = "poses" + auto_scale_poses: bool = True + colmap_path: Path = Path("dense/sparse") + load_3D_points: bool = True + depth_unit_scale_factor: float = 1e-3 + downscale_factor: Optional[int] = None + max_2D_matches_per_3D_point: int = 0 + + +@dataclass +class NerfW(DataParser): + config: NerfWDataParserConfig + + def __init__(self, config: NerfWDataParserConfig): + super().__init__(config=config) + self.data: Path = config.data + self.i_eval: list[int] = [] + + def _load_split_file(self) -> pd.DataFrame: + split_file = self.data / f"{self.config.data_name}.tsv" + if not split_file.exists(): + raise FileNotFoundError(f"Missing NeRF-W split file: {split_file}") + + split_data = pd.read_csv(split_file, sep="\t").dropna() + required_cols = {"filename", "split"} + missing = required_cols - set(split_data.columns) + if missing: + raise ValueError(f"Split file {split_file} is missing columns: {sorted(missing)}") + split_data["filename"] = split_data["filename"].astype(str) + split_data["split"] = split_data["split"].astype(str).str.lower() + return split_data + + def _generate_dataparser_outputs(self, split: str = "train") -> DataparserOutputs: + image_filenames: list[Path] = [] + poses: list[torch.Tensor] = [] + fxs: list[torch.Tensor] = [] + fys: list[torch.Tensor] = [] + cxs: list[torch.Tensor] = [] + cys: list[torch.Tensor] = [] + + colmap_path = self.data / self.config.colmap_path + cameras_path = colmap_path / "cameras.bin" + images_path = colmap_path / "images.bin" + + with CONSOLE.status(f"[bold green]Reading phototourism images and poses for {split} split..."): + cams = colmap_utils.read_cameras_binary(cameras_path) + imgs = colmap_utils.read_images_binary(images_path) + + split_data = self._load_split_file() + split_filenames = set(split_data["filename"].tolist()) + + # Iterate images, then resolve the owning camera via image.camera_id. + for _, img in sorted(imgs.items(), key=lambda kv: kv[1].name): + if img.name not in split_filenames: + continue + cam = cams[img.camera_id] + if cam.model != "PINHOLE": + raise ValueError( + f"Only PINHOLE cameras are currently supported; got {cam.model} for image {img.name}" + ) + + pose = torch.cat( + [torch.tensor(img.qvec2rotmat()), torch.tensor(img.tvec.reshape(3, 1))], + dim=1, + ) + pose = torch.cat([pose, torch.tensor([[0.0, 0.0, 0.0, 1.0]])], dim=0) + poses.append(torch.linalg.inv(pose)) + fxs.append(torch.tensor(cam.params[0])) + fys.append(torch.tensor(cam.params[1])) + cxs.append(torch.tensor(cam.params[2])) + cys.append(torch.tensor(cam.params[3])) + image_filenames.append(self.data / "dense/images" / img.name) + + if not image_filenames: + raise ValueError(f"No valid images found for dataset at {self.data}") + + poses_t = torch.stack(poses).float() + poses_t[..., 1:3] *= -1 + fxs_t = torch.stack(fxs).float() + fys_t = torch.stack(fys).float() + cxs_t = torch.stack(cxs).float() + cys_t = torch.stack(cys).float() + + filename_to_index = {path.name: idx for idx, path in enumerate(image_filenames)} + eval_names = split_data.loc[split_data["split"] == "test", "filename"].tolist() + eval_indices = [filename_to_index[name] for name in eval_names if name in filename_to_index] + eval_indices_t = torch.tensor(eval_indices, dtype=torch.long) + self.i_eval = eval_indices + + CONSOLE.log(f"eval_indices: {eval_indices_t}") + CONSOLE.log(f"eval_filenames: {[image_filenames[i] for i in eval_indices]}") + + all_indices = torch.arange(len(image_filenames), dtype=torch.long) + if split == "train": + # Preserve original behavior: keep all images in train, while the datamanager + # applies masking to eval-designated images. + indices = all_indices + elif split in {"val", "test"}: + indices = eval_indices_t + else: + raise ValueError(f"Unknown dataparser split {split}") + + poses_t, transform_matrix = camera_utils.auto_orient_and_center_poses( + poses_t, + method=self.config.orientation_method, + center_method=self.config.center_method, + ) + + scale_factor = 1.0 + if self.config.auto_scale_poses: + scale_factor /= float(torch.max(torch.abs(poses_t[:, :3, 3])).clamp_min(1e-6)) + scale_factor *= self.config.scale_factor + poses_t[:, :3, 3] *= scale_factor + + aabb_scale = self.config.scene_scale + scene_box = SceneBox( + aabb=torch.tensor( + [[-aabb_scale, -aabb_scale, -aabb_scale], [aabb_scale, aabb_scale, aabb_scale]], + dtype=torch.float32, + ) + ) + + cameras = Cameras( + camera_to_worlds=poses_t[:, :3, :4], + fx=fxs_t, + fy=fys_t, + cx=cxs_t, + cy=cys_t, + camera_type=CameraType.PERSPECTIVE, + ) + cameras = cameras[indices] + selected_filenames = [image_filenames[i] for i in indices.tolist()] + + metadata = {} + if split == "train" and self.config.load_3D_points: + metadata.update(self._load_3D_points(colmap_path, transform_matrix, scale_factor)) + + if len(cameras) != len(selected_filenames): + raise RuntimeError("Cameras / image filename count mismatch after split selection") + + return DataparserOutputs( + image_filenames=selected_filenames, + cameras=cameras, + scene_box=scene_box, + dataparser_scale=scale_factor, + dataparser_transform=transform_matrix, + metadata=metadata, + ) + + def _load_3D_points(self, colmap_path: Path, transform_matrix: torch.Tensor, scale_factor: float): + if (colmap_path / "points3D.bin").exists(): + colmap_points = colmap_utils.read_points3D_binary(colmap_path / "points3D.bin") + elif (colmap_path / "points3D.txt").exists(): + colmap_points = colmap_utils.read_points3D_text(colmap_path / "points3D.txt") + else: + raise ValueError(f"Could not find points3D.txt or points3D.bin in {colmap_path}") + + points3D = torch.from_numpy(np.array([p.xyz for p in colmap_points.values()], dtype=np.float32)) + points3D = ( + torch.cat((points3D, torch.ones_like(points3D[..., :1])), dim=-1) + @ transform_matrix.T + ) + points3D *= scale_factor + + points3D_rgb = torch.from_numpy(np.array([p.rgb for p in colmap_points.values()], dtype=np.uint8)) + points3D_num_points = torch.tensor([len(p.image_ids) for p in colmap_points.values()], dtype=torch.int64) + out = { + "points3D_xyz": points3D, + "points3D_rgb": points3D_rgb, + "points3D_error": torch.from_numpy(np.array([p.error for p in colmap_points.values()], dtype=np.float32)), + "points3D_num_points2D": points3D_num_points, + } + + if self.config.max_2D_matches_per_3D_point != 0: + if (colmap_path / "images.txt").exists(): + im_id_to_image = colmap_utils.read_images_text(colmap_path / "images.txt") + elif (colmap_path / "images.bin").exists(): + im_id_to_image = colmap_utils.read_images_binary(colmap_path / "images.bin") + else: + raise ValueError(f"Could not find images.txt or images.bin in {colmap_path}") + + downscale_factor = self._downscale_factor + max_num_points = int(torch.max(points3D_num_points).item()) + if self.config.max_2D_matches_per_3D_point > 0: + max_num_points = min(max_num_points, self.config.max_2D_matches_per_3D_point) + + points3D_image_ids = [] + points3D_image_xy = [] + for p in colmap_points.values(): + nids = np.array(p.image_ids, dtype=np.int64) + nxy_ids = np.array(p.point2D_idxs, dtype=np.int32) + if self.config.max_2D_matches_per_3D_point != -1: + idxs = np.argsort(p.error)[: self.config.max_2D_matches_per_3D_point] + nids = nids[idxs] + nxy_ids = nxy_ids[idxs] + nxy = [im_id_to_image[im_id].xys[pt_idx] for im_id, pt_idx in zip(nids, nxy_ids)] + nxy = torch.from_numpy(np.stack(nxy).astype(np.float32)) if len(nxy) else torch.zeros((0, 2), dtype=torch.float32) + nids_t = torch.from_numpy(nids) + points3D_image_ids.append( + torch.cat((nids_t, torch.full((max_num_points - len(nids_t),), -1, dtype=torch.int64))) + ) + points3D_image_xy.append( + torch.cat( + ( + nxy, + torch.full((max_num_points - len(nxy), 2), 0, dtype=torch.float32), + ) + ) + / downscale_factor + ) + out["points3D_image_ids"] = torch.stack(points3D_image_ids, dim=0) + out["points3D_points2D_xy"] = torch.stack(points3D_image_xy, dim=0) + return out + + def check_in_eval(self, idx: int) -> bool: + return idx in self.i_eval + + def find_eval_idx(self, idx: int) -> int: + return self.i_eval[idx] + + +splatfactow_dataparser = DataParserSpecification(config=NerfWDataParserConfig()) diff --git a/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_field.py b/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_field.py new file mode 100644 index 0000000000..79d251ea4e --- /dev/null +++ b/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_field.py @@ -0,0 +1,174 @@ +"""Fields for Splatfacto-W. + +Forward-looking but backwards-compatible with the Nerfstudio 1.1.5 / gsplat 1.4.x +stack. The main goals here are: +- avoid unnecessary tensor repeats where possible, +- expose stable helper methods for SH export / rendering, +- keep call sites simple for later gsplat upgrades. +""" + +from __future__ import annotations + +from typing import Literal, Optional + +import torch +from torch import Tensor, nn + +from gsplat.cuda._wrapper import spherical_harmonics +from nerfstudio.cameras.rays import RayBundle +from nerfstudio.field_components import MLP +from nerfstudio.fields.base_field import Field + + +class BGField(Field): + def __init__( + self, + appearance_embedding_dim: int, + implementation: Literal["tcnn", "torch"] = "torch", + sh_levels: int = 4, + layer_width: int = 128, + num_layers: int = 3, + ): + super().__init__() + self.sh_dim = (sh_levels + 1) ** 2 + + self.encoder = MLP( + in_dim=appearance_embedding_dim, + num_layers=num_layers - 1, + layer_width=layer_width, + out_dim=layer_width, + activation=nn.ReLU(), + out_activation=nn.ReLU(), + implementation=implementation, + ) + self.sh_base_head = nn.Linear(layer_width, 3) + self.sh_rest_head = nn.Linear(layer_width, (self.sh_dim - 1) * 3) + self.sh_rest_head.weight.data.zero_() + self.sh_rest_head.bias.data.zero_() + + def _encode(self, appearance_embedding: Optional[Tensor]) -> Tensor: + if appearance_embedding is None: + raise ValueError("appearance_embedding must be provided for BGField") + if appearance_embedding.dim() == 1: + appearance_embedding = appearance_embedding.unsqueeze(0) + return self.encoder(appearance_embedding).float() + + def get_sh_coeffs( + self, + appearance_embedding: Optional[Tensor] = None, + num_sh: Optional[int] = None, + ) -> Tensor: + x = self._encode(appearance_embedding) + full_sh_dim = self.sh_dim + target_sh_dim = full_sh_dim if num_sh is None else (num_sh + 1) ** 2 + target_sh_dim = min(target_sh_dim, full_sh_dim) + + base_color = self.sh_base_head(x) + sh_rest = self.sh_rest_head(x)[..., : max(target_sh_dim - 1, 0) * 3] + return torch.cat([base_color, sh_rest], dim=-1).view(-1, target_sh_dim, 3) + + def get_background_rgb( + self, + ray_bundle: RayBundle, + appearance_embedding: Optional[Tensor] = None, + num_sh: int = 4, + ) -> Tensor: + directions = ray_bundle.directions.reshape(-1, 3) + sh_coeffs = self.get_sh_coeffs(appearance_embedding=appearance_embedding, num_sh=num_sh) + if sh_coeffs.shape[0] == 1 and directions.shape[0] != 1: + sh_coeffs = sh_coeffs.expand(directions.shape[0], -1, -1) + elif sh_coeffs.shape[0] != directions.shape[0]: + raise ValueError( + f"BGField SH coeff batch ({sh_coeffs.shape[0]}) does not match direction batch ({directions.shape[0]})" + ) + return spherical_harmonics(degrees_to_use=num_sh, dirs=directions, coeffs=sh_coeffs) + + def forward( + self, + ray_bundle: RayBundle, + appearance_embedding: Optional[Tensor] = None, + num_sh: Optional[int] = None, + ) -> Tensor: + if num_sh is None: + num_sh = int(round(self.sh_dim**0.5)) - 1 + return self.get_background_rgb( + ray_bundle=ray_bundle, + appearance_embedding=appearance_embedding, + num_sh=num_sh, + ) + + +class SplatfactoWField(Field): + def __init__( + self, + appearance_embed_dim: int, + appearance_features_dim: int, + implementation: Literal["tcnn", "torch"] = "torch", + sh_levels: int = 4, + num_layers: int = 3, + layer_width: int = 256, + ): + super().__init__() + self.sh_dim = (sh_levels + 1) ** 2 + self.encoder = MLP( + in_dim=appearance_embed_dim + appearance_features_dim, + num_layers=num_layers - 1, + layer_width=layer_width, + out_dim=layer_width, + activation=nn.ReLU(), + out_activation=nn.ReLU(), + implementation=implementation, + ) + self.sh_base_head = nn.Linear(layer_width, 3) + self.sh_rest_head = nn.Linear(layer_width, (self.sh_dim - 1) * 3) + self.sh_rest_head.weight.data.zero_() + self.sh_rest_head.bias.data.zero_() + + def _encode(self, appearance_embed: Tensor, appearance_features: Tensor) -> Tensor: + if appearance_embed.dim() == 1: + appearance_embed = appearance_embed.unsqueeze(0) + if appearance_embed.shape[0] == 1 and appearance_features.shape[0] != 1: + appearance_embed = appearance_embed.expand(appearance_features.shape[0], -1) + elif appearance_embed.shape[0] != appearance_features.shape[0]: + raise ValueError( + f"appearance_embed batch ({appearance_embed.shape[0]}) must be 1 or match appearance_features batch ({appearance_features.shape[0]})" + ) + x = torch.cat((appearance_embed, appearance_features), dim=-1) + return self.encoder(x).float() + + def get_sh_coeffs( + self, + appearance_embed: Tensor, + appearance_features: Tensor, + num_sh: Optional[int] = None, + ) -> Tensor: + x = self._encode(appearance_embed, appearance_features) + full_sh_dim = self.sh_dim + target_sh_dim = full_sh_dim if num_sh is None else (num_sh + 1) ** 2 + target_sh_dim = min(target_sh_dim, full_sh_dim) + + base_color = self.sh_base_head(x) + sh_rest = self.sh_rest_head(x)[..., : max(target_sh_dim - 1, 0) * 3] + return torch.cat([base_color, sh_rest], dim=-1).view(-1, target_sh_dim, 3) + + def forward( + self, + appearance_embed: Tensor, + appearance_features: Tensor, + num_sh: Optional[int] = None, + ) -> Tensor: + return self.get_sh_coeffs( + appearance_embed=appearance_embed, + appearance_features=appearance_features, + num_sh=num_sh, + ) + + def shs_0(self, appearance_embed: Tensor, appearance_features: Tensor) -> Tensor: + x = self._encode(appearance_embed, appearance_features) + base_color = self.sh_base_head(x) + return base_color.view(-1, 3) + + def shs_rest(self, appearance_embed: Tensor, appearance_features: Tensor) -> Tensor: + x = self._encode(appearance_embed, appearance_features) + sh_rest = self.sh_rest_head(x) + return sh_rest.view(-1, self.sh_dim - 1, 3) diff --git a/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model.py b/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model.py new file mode 100644 index 0000000000..8e9765caa9 --- /dev/null +++ b/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model.py @@ -0,0 +1,958 @@ +from __future__ import annotations + +import math +from dataclasses import dataclass, field +from typing import Any, Dict, List, Literal, Optional, Tuple, Type, Union + +import numpy as np +import torch +import torch.nn.functional as F +from gsplat.cuda._wrapper import spherical_harmonics +from pytorch_msssim import SSIM +from torch import Tensor +from torch.nn import Parameter + +try: + from gsplat.rendering import rasterization +except ImportError as exc: # pragma: no cover + raise ImportError("Please install gsplat>=1.4.0") from exc + +from nerfstudio.cameras.camera_optimizers import CameraOptimizer, CameraOptimizerConfig +from nerfstudio.cameras.camera_utils import normalize +from nerfstudio.cameras.cameras import Cameras +from nerfstudio.data.scene_box import OrientedBox +from nerfstudio.engine.callbacks import ( + TrainingCallback, + TrainingCallbackAttributes, + TrainingCallbackLocation, +) +from nerfstudio.engine.optimizers import Optimizers +from nerfstudio.models.base_model import Model, ModelConfig +from nerfstudio.utils.colors import get_color +from nerfstudio.utils.misc import torch_compile +from nerfstudio.utils.rich_utils import CONSOLE +from nerfstudio.models.splatfacto import SplatfactoModel +from splatfactow.splatfactow_field import BGField, SplatfactoWField + + +def quat_to_rotmat(quats: Tensor) -> Tensor: + """Convert quaternions to rotation matrices.""" + quats = F.normalize(quats, p=2, dim=-1) + w, x, y, z = torch.unbind(quats, dim=-1) + rot = torch.stack( + [ + 1 - 2 * (y**2 + z**2), + 2 * (x * y - w * z), + 2 * (x * z + w * y), + 2 * (x * y + w * z), + 1 - 2 * (x**2 + z**2), + 2 * (y * z - w * x), + 2 * (x * z - w * y), + 2 * (y * z + w * x), + 1 - 2 * (x**2 + y**2), + ], + dim=-1, + ) + return rot.reshape(quats.shape[:-1] + (3, 3)) + +def random_quat_tensor(num: int, *, device: Optional[torch.device] = None) -> Tensor: + """Sample random quaternions.""" + u = torch.rand(num, device=device) + v = torch.rand(num, device=device) + w = torch.rand(num, device=device) + return torch.stack( + [ + torch.sqrt(1 - u) * torch.sin(2 * math.pi * v), + torch.sqrt(1 - u) * torch.cos(2 * math.pi * v), + torch.sqrt(u) * torch.sin(2 * math.pi * w), + torch.sqrt(u) * torch.cos(2 * math.pi * w), + ], + dim=-1, + ) + + +def resize_image(image: torch.Tensor, d: int) -> torch.Tensor: + """Area-style downscale, matching Nerfstudio's splatfacto helper.""" + image = image.to(torch.float32) + weight = (1.0 / (d * d)) * torch.ones((1, 1, d, d), dtype=torch.float32, device=image.device) + return ( + F.conv2d(image.permute(2, 0, 1)[:, None, ...], weight, stride=d) + .squeeze(1) + .permute(1, 2, 0) + ) + + +@torch_compile() +def get_viewmat(optimized_camera_to_world: Tensor) -> Tensor: + """Convert c2w to gsplat world2camera matrices.""" + rot = optimized_camera_to_world[:, :3, :3] + trans = optimized_camera_to_world[:, :3, 3:4] + rot = rot * torch.tensor([[[1, -1, -1]]], device=rot.device, dtype=rot.dtype) + rot_inv = rot.transpose(1, 2) + trans_inv = -torch.bmm(rot_inv, trans) + viewmat = torch.zeros(rot.shape[0], 4, 4, device=rot.device, dtype=rot.dtype) + viewmat[:, 3, 3] = 1.0 + viewmat[:, :3, :3] = rot_inv + viewmat[:, :3, 3:4] = trans_inv + return viewmat + + +@dataclass +class SplatfactoWModelConfig(ModelConfig): + _target: Type = field(default_factory=lambda: SplatfactoWModel) + warmup_length: int = 1000 + refine_every: int = 100 + resolution_schedule: int = 3000 + background_color: Literal["random", "black", "white"] = "random" + num_downscales: int = 2 + cull_alpha_thresh: float = 0.1 + cull_scale_thresh: float = 0.5 + continue_cull_post_densification: bool = True + reset_alpha_every: int = 25 + densify_grad_thresh: float = 0.0008 + densify_size_thresh: float = 0.01 + n_split_samples: int = 2 + cull_screen_size: float = 0.15 + split_screen_size: float = 0.05 + stop_screen_size_at: int = 15000 + random_init: bool = False + num_random: int = 50000 + random_scale: float = 10.0 + ssim_lambda: float = 0.2 + stop_split_at: int = 20000 + use_scale_regularization: bool = False + max_gauss_ratio: float = 10.0 + output_depth_during_training: bool = False + rasterize_mode: Literal["classic", "antialiased"] = "antialiased" + camera_optimizer: CameraOptimizerConfig = field(default_factory=lambda: CameraOptimizerConfig(mode="off")) + enable_bg_model: bool = True + bg_num_layers: int = 3 + bg_layer_width: int = 128 + implementation: Literal["tcnn", "torch"] = "torch" + appearance_embed_dim: int = 48 + app_num_layers: int = 3 + app_layer_width: int = 256 + enable_alpha_loss: bool = True + appearance_features_dim: int = 72 + enable_robust_mask: bool = True + robust_mask_percentage: Tuple[float, float] = (0.0, 0.40) + robust_mask_reset_interval: int = 6000 + never_mask_upper: float = 0.4 + start_robust_mask_at: int = 6000 + sh_degree_interval: int = 2000 + sh_degree: int = 3 + bg_sh_degree: int = 4 + use_avg_appearance: bool = False + eval_right_half: bool = False + max_new_gaussians_per_refine: int = 500_000 + """Safety cap for split+duplicate growth during one refine step.""" + use_eval_cache: bool = True + """Cache per-camera appearance/sh results during eval only.""" + tile_size: int = 16 + """Forward-looking knob kept separate so future gsplat updates are localized.""" + +class SplatfactoWModel(SplatfactoModel): + config: SplatfactoWModelConfig + + def __init__( + self, + *args, + seed_points: Optional[Tuple[torch.Tensor, torch.Tensor]] = None, + **kwargs, + ): + self.seed_points = seed_points + super().__init__(*args, **kwargs) + def get_sh_coeffs(self, cam_idx: Optional[int] = None) -> torch.Tensor: + device=self.appearance_features.device + if cam_idx is not None: + embed = self.appearance_embeds(torch.tensor(cam_idx, device=self.appearance_features.device)) + elif self.config.use_avg_appearance: + embed = self.appearance_embeds.weight.mean(dim=0) + else: + embed = self.appearance_embeds(torch.tensor(0, device=self.appearance_features.device)) + + embed_expanded = embed.unsqueeze(0).expand(self.appearance_features.shape[0], -1) + return self.color_nn(embed_expanded, self.appearance_features) + + def populate_modules(self) -> None: + device = torch.device(self.kwargs["device"]) + if self.seed_points is not None and not self.config.random_init: + means = torch.nn.Parameter(self.seed_points[0].to(device)) + else: + means = torch.nn.Parameter((torch.rand((self.config.num_random, 3), device=device) - 0.5) * self.config.random_scale) + + self.xys_grad_norm: Optional[Tensor] = None + self.vis_counts: Optional[Tensor] = None + self.max_2Dsize: Optional[Tensor] = None + self.xys: Optional[Tensor] = None + self.radii: Optional[Tensor] = None + + distances, _ = self.k_nearest_sklearn(means.data, 3) + distances_t = torch.from_numpy(distances).to(device) + avg_dist = distances_t.mean(dim=-1, keepdim=True).clamp_min(1e-6) + scales = torch.nn.Parameter(torch.log(avg_dist.repeat(1, 3))) + num_points = means.shape[0] + quats = torch.nn.Parameter(random_quat_tensor(num_points, device=device)) + appearance_features = torch.nn.Parameter(torch.zeros((num_points, self.config.appearance_features_dim), device=device)) + + if self.seed_points is not None and self.seed_points[1].shape[0] > 0: + colors = torch.nn.Parameter((self.seed_points[1].to(device).float() / 255.0).clamp(0.0, 1.0)) + else: + colors = torch.nn.Parameter(torch.zeros((num_points, 3), device=device)) + + opacities = torch.nn.Parameter(torch.logit(0.1 * torch.ones(num_points, 1, device=device))) + self.gauss_params = torch.nn.ParameterDict( + { + "means": means, + "scales": scales, + "quats": quats, + "appearance_features": appearance_features, + "colors": colors, + "opacities": opacities, + } + ) + + self.camera_optimizer = self.config.camera_optimizer.setup(num_cameras=self.num_train_data, device="cpu") + + from torchmetrics.image import PeakSignalNoiseRatio + from torchmetrics.image.lpip import LearnedPerceptualImagePatchSimilarity + + self.max_loss = 0.0 + self.min_loss = 1e10 + self.psnr = PeakSignalNoiseRatio(data_range=1.0) + self.ssim = SSIM(data_range=1.0, size_average=True, channel=3) + self.lpips = LearnedPerceptualImagePatchSimilarity(normalize=True) + self.step = 0 + self.optimizers: Optional[Dict[str, torch.optim.Optimizer]] = None + + self.crop_box: Optional[OrientedBox] = None + if self.config.background_color == "random": + self.background_color = torch.tensor([0.1490, 0.1647, 0.2157], device=device) + else: + self.background_color = get_color(self.config.background_color).to(device) + + self.appearance_embeds = torch.nn.Embedding(self.num_train_data, self.config.appearance_embed_dim).to(device) + self.bg_model = ( + BGField( + appearance_embedding_dim=self.config.appearance_embed_dim, + implementation=self.config.implementation, + sh_levels=self.config.bg_sh_degree, + num_layers=self.config.bg_num_layers, + layer_width=self.config.bg_layer_width, + ).to(device) + if self.config.enable_bg_model + else None + ) + self.color_nn = SplatfactoWField( + appearance_embed_dim=self.config.appearance_embed_dim, + appearance_features_dim=self.config.appearance_features_dim, + implementation=self.config.implementation, + sh_levels=self.config.sh_degree, + num_layers=self.config.app_num_layers, + layer_width=self.config.app_layer_width, + ).to(device) + + self._eval_cache: Dict[str, Any] = {"cam_idx": None, "num_points": None, "colors": None, "bg_sh": None} + self.camera_idx = 0 + self.last_size = (1, 1) + + def set_camera_idx(self, cam_idx: int) -> None: + self.camera_idx = int(cam_idx) + + @property + def num_points(self) -> int: + return self.means.shape[0] + + @property + def means(self) -> Parameter: + return self.gauss_params["means"] + + @property + def scales(self) -> Parameter: + return self.gauss_params["scales"] + + @property + def quats(self) -> Parameter: + return self.gauss_params["quats"] + + @property + def appearance_features(self) -> Parameter: + return self.gauss_params["appearance_features"] + + @property + def base_colors(self) -> Parameter: + return self.gauss_params["colors"] + + @property + def opacities(self) -> Parameter: + return self.gauss_params["opacities"] + + def load_state_dict(self, state_dict, **kwargs): # type: ignore[override] + self.step = 30000 + if "means" in state_dict: + for name in ["means", "scales", "quats", "appearance_features", "opacities", "colors"]: + state_dict[f"gauss_params.{name}"] = state_dict[name] + new_count = state_dict["gauss_params.means"].shape[0] + for name, param in self.gauss_params.items(): + new_shape = (new_count,) + param.shape[1:] + self.gauss_params[name] = torch.nn.Parameter(torch.zeros(new_shape, device=self.device, dtype=param.dtype)) + super().load_state_dict(state_dict, **kwargs) + self._reset_eval_cache() + + def k_nearest_sklearn(self, x: torch.Tensor, k: int) -> Tuple[np.ndarray, np.ndarray]: + from sklearn.neighbors import NearestNeighbors + + x_np = x.detach().cpu().numpy() + nn_model = NearestNeighbors(n_neighbors=k + 1, algorithm="auto", metric="euclidean").fit(x_np) + distances, indices = nn_model.kneighbors(x_np) + return distances[:, 1:].astype(np.float32), indices[:, 1:].astype(np.float32) + + def _reset_eval_cache(self) -> None: + self._eval_cache = {"cam_idx": None, "num_points": None, "colors": None, "bg_sh": None} + + def set_crop(self, crop_box: Optional[OrientedBox]) -> None: + self.crop_box = crop_box + + def set_background(self, background_color: torch.Tensor) -> None: + assert background_color.shape == (3,) + self.background_color = background_color.to(self.device) + + @staticmethod + def _metadata_cam_idx(camera: Cameras) -> Optional[int]: + if camera.metadata is None or "cam_idx" not in camera.metadata: + return None + cam_idx = camera.metadata["cam_idx"] + if isinstance(cam_idx, torch.Tensor): + return int(cam_idx.item()) + return int(cam_idx) + + def _appearance_embed_for_camera(self, camera: Cameras) -> Tuple[torch.Tensor, Optional[int]]: + cam_idx = self._metadata_cam_idx(camera) + if cam_idx is not None: + return self.appearance_embeds(torch.tensor(cam_idx, device=self.device)), cam_idx + if self.config.use_avg_appearance: + return self.appearance_embeds.weight.mean(dim=0), None + return self.appearance_embeds(torch.tensor(0, device=self.device)), None + + def _should_use_eval_cache(self, cam_idx: Optional[int]) -> bool: + if self.training or not self.config.use_eval_cache or cam_idx is None: + return False + return ( + self._eval_cache["cam_idx"] == cam_idx + and self._eval_cache["num_points"] == self.num_points + ) + + def _compute_colors(self, appearance_embed: torch.Tensor, use_cache: bool) -> torch.Tensor: + if use_cache and self._eval_cache["colors"] is not None: + return self._eval_cache["colors"] + embed = appearance_embed.unsqueeze(0).expand(self.appearance_features.shape[0], -1) + colors = self.color_nn(embed, self.appearance_features).float() + if not self.training: + self._eval_cache["colors"] = colors + self._eval_cache["num_points"] = self.num_points + return colors + + def _compute_bg_sh(self, appearance_embed: torch.Tensor, use_cache: bool) -> Optional[torch.Tensor]: + if self.bg_model is None: + return None + if use_cache and self._eval_cache["bg_sh"] is not None: + return self._eval_cache["bg_sh"] + bg_sh = self.bg_model.get_sh_coeffs(appearance_embedding=appearance_embed) + if not self.training: + self._eval_cache["bg_sh"] = bg_sh + self._eval_cache["num_points"] = self.num_points + return bg_sh + + def _resolve_means2d_and_radii(self, info: Dict[str, Any]) -> Tuple[Optional[Tensor], Optional[Tensor]]: + means2d = info.get("means2d") + if means2d is None: + means2d = info.get("gaussian_ids") # forward-looking fallback; may remain None + radii = info.get("radii") + if isinstance(radii, torch.Tensor) and radii.dim() > 1: + radii = radii[0] + return means2d, radii + + def _rasterize( + self, + *, + means: Tensor, + quats: Tensor, + scales: Tensor, + opacities: Tensor, + colors: Tensor, + viewmats: Tensor, + intrinsics: Tensor, + width: int, + height: int, + render_mode: str, + sh_degree: int, + ) -> Tuple[Tensor, Tensor, Dict[str, Any]]: + kwargs = dict( + means=means, + quats=quats, + scales=scales, + opacities=opacities, + colors=colors, + viewmats=viewmats, + Ks=intrinsics, + width=width, + height=height, + packed=False, + near_plane=0.01, + far_plane=1e10, + render_mode=render_mode, + sh_degree=sh_degree, + sparse_grad=False, + absgrad=True, + rasterize_mode=self.config.rasterize_mode, + ) + try: + return rasterization(tile_size=self.config.tile_size, **kwargs) + except TypeError: + # Forward-looking fallback if tile_size disappears in a future gsplat. + return rasterization(**kwargs) + + def _replace_optimizer_param(self, optimizer: torch.optim.Optimizer, new_param: Parameter, old_mask: Optional[torch.Tensor] = None) -> None: + old_param = optimizer.param_groups[0]["params"][0] + state = optimizer.state.pop(old_param, {}) + new_state: Dict[str, Any] = {} + for key, value in state.items(): + if torch.is_tensor(value): + if old_mask is not None and value.shape[:1] == old_mask.shape[:1]: + new_state[key] = value[old_mask] + else: + new_state[key] = value + else: + new_state[key] = value + optimizer.param_groups[0]["params"][0] = new_param + optimizer.state[new_param] = new_state + + def remove_from_optim(self, optimizer: torch.optim.Optimizer, keep_mask: torch.Tensor, new_param: Parameter) -> None: + self._replace_optimizer_param(optimizer, new_param, old_mask=keep_mask) + + def remove_from_all_optim(self, optimizers: Optimizers, keep_mask: torch.Tensor) -> None: + for group, params in self.get_gaussian_param_groups().items(): + self.remove_from_optim(optimizers.optimizers[group], keep_mask, params[0]) + torch.cuda.empty_cache() + + def _append_optimizer_zeros(self, optimizer: torch.optim.Optimizer, old_count: int, new_param: Parameter) -> None: + old_param = optimizer.param_groups[0]["params"][0] + state = optimizer.state.pop(old_param, {}) + new_state: Dict[str, Any] = {} + new_count = new_param.shape[0] + for key, value in state.items(): + if torch.is_tensor(value) and value.shape[:1] == (old_count,): + pad_shape = (new_count - old_count,) + value.shape[1:] + pad = torch.zeros(pad_shape, dtype=value.dtype, device=value.device) + new_state[key] = torch.cat([value, pad], dim=0) + else: + new_state[key] = value + optimizer.param_groups[0]["params"][0] = new_param + optimizer.state[new_param] = new_state + + def sync_optimizers_after_append(self, optimizers: Optimizers, old_count: int) -> None: + for group, params in self.get_gaussian_param_groups().items(): + self._append_optimizer_zeros(optimizers.optimizers[group], old_count, params[0]) + + @torch.no_grad() + def after_train(self, step: int) -> None: + assert step == self.step + if self.step >= self.config.stop_split_at or self.xys is None or self.radii is None: + return + visible_mask = (self.radii > 0).flatten() + if not torch.any(visible_mask): + return + grad_source = getattr(self.xys, "absgrad", None) + if grad_source is None: + grad_source = self.xys.grad + if grad_source is None: + return + grads = grad_source[0][visible_mask].norm(dim=-1).clamp_max(1e3) + if self.xys_grad_norm is None: + self.xys_grad_norm = torch.zeros(self.num_points, device=self.device, dtype=torch.float32) + self.vis_counts = torch.ones(self.num_points, device=self.device, dtype=torch.float32) + assert self.vis_counts is not None + self.vis_counts[visible_mask] += 1 + self.xys_grad_norm[visible_mask] += grads + if self.max_2Dsize is None: + self.max_2Dsize = torch.zeros(self.num_points, device=self.device, dtype=torch.float32) + new_radii = self.radii.detach()[visible_mask] + self.max_2Dsize[visible_mask] = torch.maximum( + self.max_2Dsize[visible_mask], + new_radii / float(max(self.last_size[0], self.last_size[1])), + ) + + @torch.no_grad() + def refinement_after(self, optimizers: Optimizers, step: int) -> None: + assert step == self.step + if self.step <= self.config.warmup_length: + return + reset_interval = self.config.reset_alpha_every * self.config.refine_every + do_densification = ( + self.step < self.config.stop_split_at + and self.step % reset_interval > self.num_train_data + self.config.refine_every + ) + if do_densification: + assert self.xys_grad_norm is not None and self.vis_counts is not None and self.max_2Dsize is not None + avg_grad_norm = ((self.xys_grad_norm / self.vis_counts) * 0.5 * max(self.last_size[0], self.last_size[1])).clamp_max(10.0) + high_grads = (avg_grad_norm > self.config.densify_grad_thresh).squeeze() + splits = (self.scales.exp().max(dim=-1).values > self.config.densify_size_thresh).squeeze() & high_grads + if self.step < self.config.stop_screen_size_at: + splits |= (self.max_2Dsize > self.config.split_screen_size).squeeze() & high_grads + dups = (self.scales.exp().max(dim=-1).values <= self.config.densify_size_thresh).squeeze() & high_grads + + split_count = int(splits.sum().item()) + dup_count = int(dups.sum().item()) + proposed_new = split_count * self.config.n_split_samples + dup_count + if proposed_new > self.config.max_new_gaussians_per_refine: + keep_fraction = self.config.max_new_gaussians_per_refine / max(proposed_new, 1) + split_budget = max(1, int(split_count * keep_fraction)) if split_count > 0 else 0 + dup_budget = max(0, self.config.max_new_gaussians_per_refine - split_budget * self.config.n_split_samples) + if split_count > split_budget: + idx = torch.where(splits)[0][:split_budget] + limited = torch.zeros_like(splits) + limited[idx] = True + splits = limited + if dup_count > dup_budget: + idx = torch.where(dups)[0][:dup_budget] + limited = torch.zeros_like(dups) + limited[idx] = True + dups = limited + + split_params = self.split_gaussians(splits, self.config.n_split_samples) + dup_params = self.dup_gaussians(dups) + old_count = self.num_points + for name, param in self.gauss_params.items(): + self.gauss_params[name] = torch.nn.Parameter(torch.cat([param.detach(), split_params[name], dup_params[name]], dim=0)) + if self.max_2Dsize is not None: + self.max_2Dsize = torch.cat( + [ + self.max_2Dsize, + torch.zeros(split_params["means"].shape[0], device=self.device), + torch.zeros(dup_params["means"].shape[0], device=self.device), + ], + dim=0, + ) + self.sync_optimizers_after_append(optimizers, old_count) + keep_mask = ~torch.cat( + [ + splits, + torch.zeros(split_params["means"].shape[0] + dup_params["means"].shape[0], device=self.device, dtype=torch.bool), + ], + dim=0, + ) + keep_mask = self.cull_gaussians(keep_mask=keep_mask) + elif self.step >= self.config.stop_split_at and self.config.continue_cull_post_densification: + keep_mask = self.cull_gaussians() + else: + keep_mask = None + + if keep_mask is not None: + self.remove_from_all_optim(optimizers, keep_mask) + + if self.step < self.config.stop_split_at and self.step % reset_interval == self.config.refine_every: + reset_value = self.config.cull_alpha_thresh * 2.0 + self.opacities.data = torch.clamp( + self.opacities.data, + max=torch.logit(torch.tensor(reset_value, device=self.device)).item(), + ) + optim = optimizers.optimizers["opacities"] + param = optim.param_groups[0]["params"][0] + state = optim.state.get(param, None) + if state is not None and "exp_avg" in state: + state["exp_avg"].zero_() + state["exp_avg_sq"].zero_() + + self.xys_grad_norm = None + self.vis_counts = None + self.max_2Dsize = None + self._reset_eval_cache() + + @torch.no_grad() + def cull_gaussians(self, keep_mask: Optional[torch.Tensor] = None) -> Optional[torch.Tensor]: + n_before = self.num_points + keep = (torch.sigmoid(self.opacities) >= self.config.cull_alpha_thresh).squeeze() + below_alpha_count = int((~keep).sum().item()) + too_big_count = 0 + if self.step > self.config.refine_every * self.config.reset_alpha_every: + too_big = (torch.exp(self.scales).max(dim=-1).values <= self.config.cull_scale_thresh).squeeze() + if self.step < self.config.stop_screen_size_at and self.max_2Dsize is not None: + too_big &= (self.max_2Dsize <= self.config.cull_screen_size).squeeze() + too_big_count = int((~too_big).sum().item()) + keep &= too_big + if keep_mask is not None: + keep &= keep_mask + for name, param in self.gauss_params.items(): + self.gauss_params[name] = torch.nn.Parameter(param[keep]) + CONSOLE.log( + f"Culled {n_before - self.num_points} gaussians " + f"({below_alpha_count} below alpha thresh, {too_big_count} too big, {self.num_points} remaining)" + ) + self._reset_eval_cache() + return keep + + @torch.no_grad() + def split_gaussians(self, split_mask: torch.Tensor, samples: int) -> Dict[str, Tensor]: + n_splits = int(split_mask.sum().item()) + if n_splits == 0: + return {name: param[:0].clone() for name, param in self.gauss_params.items()} + CONSOLE.log(f"Splitting {n_splits}/{self.num_points} gaussians") + centered = torch.randn((samples * n_splits, 3), device=self.device) + scaled = torch.exp(self.scales[split_mask]).repeat(samples, 1) * centered + quats = F.normalize(self.quats[split_mask], dim=-1) + rots = quat_to_rotmat(quats.repeat(samples, 1)) + rotated = torch.bmm(rots, scaled[..., None]).squeeze(-1) + new_means = rotated + self.means[split_mask].repeat(samples, 1) + size_fac = 1.6 + new_scales = torch.log(torch.exp(self.scales[split_mask]) / size_fac).repeat(samples, 1) + self.scales.data[split_mask] = torch.log(torch.exp(self.scales.data[split_mask]) / size_fac) + out = { + "means": new_means, + "appearance_features": self.appearance_features[split_mask].repeat(samples, 1), + "colors": self.base_colors[split_mask].repeat(samples, 1), + "opacities": self.opacities[split_mask].repeat(samples, 1), + "scales": new_scales, + "quats": self.quats[split_mask].repeat(samples, 1), + } + return out + + @torch.no_grad() + def dup_gaussians(self, dup_mask: torch.Tensor) -> Dict[str, Tensor]: + n_dups = int(dup_mask.sum().item()) + if n_dups == 0: + return {name: param[:0].clone() for name, param in self.gauss_params.items()} + CONSOLE.log(f"Duplicating {n_dups}/{self.num_points} gaussians") + return {name: param[dup_mask].clone() for name, param in self.gauss_params.items()} + + def get_training_callbacks(self, training_callback_attributes: TrainingCallbackAttributes) -> List[TrainingCallback]: + return [ + TrainingCallback([TrainingCallbackLocation.BEFORE_TRAIN_ITERATION], self.step_cb), + TrainingCallback([TrainingCallbackLocation.AFTER_TRAIN_ITERATION], self.after_train), + TrainingCallback( + [TrainingCallbackLocation.AFTER_TRAIN_ITERATION], + self.refinement_after, + update_every_num_iters=self.config.refine_every, + args=[training_callback_attributes.optimizers], + ), + ] + + def step_cb(self, step: int) -> None: + self.step = step + + def get_gaussian_param_groups(self) -> Dict[str, List[Parameter]]: + return { + name: [self.gauss_params[name]] + for name in ["means", "scales", "quats", "appearance_features", "opacities"] + } + + def get_param_groups(self) -> Dict[str, List[Parameter]]: + groups = self.get_gaussian_param_groups() + self.camera_optimizer.get_param_groups(param_groups=groups) + if self.config.enable_bg_model and self.bg_model is not None: + groups["field_background_encoder"] = list(self.bg_model.encoder.parameters()) + groups["field_background_base"] = list(self.bg_model.sh_base_head.parameters()) + groups["field_background_rest"] = list(self.bg_model.sh_rest_head.parameters()) + groups["appearance_embed"] = list(self.appearance_embeds.parameters()) + groups["appearance_model_encoder"] = list(self.color_nn.encoder.parameters()) + groups["appearance_model_base"] = list(self.color_nn.sh_base_head.parameters()) + groups["appearance_model_rest"] = list(self.color_nn.sh_rest_head.parameters()) + return groups + + def _get_downscale_factor(self) -> int: + if self.training: + return 2 ** max(self.config.num_downscales - self.step // self.config.resolution_schedule, 0) + return 1 + + def _downscale_if_required(self, image: torch.Tensor) -> torch.Tensor: + d = self._get_downscale_factor() + return resize_image(image, d) if d > 1 else image + + @staticmethod + def get_empty_outputs(width: int, height: int, background: torch.Tensor) -> Dict[str, Union[torch.Tensor, List]]: + rgb = background.repeat(height, width, 1) + depth = background.new_ones(*rgb.shape[:2], 1) * 10 + accumulation = background.new_zeros(*rgb.shape[:2], 1) + return {"rgb": rgb, "depth": depth, "accumulation": accumulation, "background": background} + + def _get_background_color(self) -> Tensor: + if self.config.background_color == "random": + return torch.rand(3, device=self.device) if self.training else self.background_color.to(self.device) + if self.config.background_color == "white": + return torch.ones(3, device=self.device) + if self.config.background_color == "black": + return torch.zeros(3, device=self.device) + raise ValueError(f"Unknown background color {self.config.background_color}") + + def get_outputs(self, camera: Cameras) -> Dict[str, Union[torch.Tensor, List]]: + if not isinstance(camera, Cameras): + CONSOLE.log("Called get_outputs with not a camera") + return {} + + sh_degree_to_use = 0 + bg_sh_degree_to_use = 0 + if self.config.sh_degree > 0: + sh_degree_to_use = min(self.step // self.config.sh_degree_interval, self.config.sh_degree) + bg_interval = max(self.config.sh_degree_interval // 2, 1) + bg_sh_degree_to_use = min(self.step // bg_interval, self.config.bg_sh_degree) + + appearance_embed, cam_idx = self._appearance_embed_for_camera(camera) + use_cache = self._should_use_eval_cache(cam_idx) + if cam_idx is not None and not self.training: + self._eval_cache["cam_idx"] = cam_idx + + if self.training: + assert camera.shape[0] == 1, "Only one camera at a time" + optimized_camera_to_world = self.camera_optimizer.apply_to_camera(camera) + else: + optimized_camera_to_world = camera.camera_to_worlds + + crop_ids: Optional[torch.Tensor] + if self.crop_box is not None and not self.training: + crop_ids = self.crop_box.within(self.means).squeeze() + if crop_ids.sum() == 0: + return self.get_empty_outputs(int(camera.width.item()), int(camera.height.item()), self.background_color) + else: + crop_ids = None + + if crop_ids is None: + means = self.means + opacities = self.opacities + scales = self.scales + quats = self.quats + appearance_features = self.appearance_features + colors_param = self.base_colors + else: + means = self.means[crop_ids] + opacities = self.opacities[crop_ids] + scales = self.scales[crop_ids] + quats = self.quats[crop_ids] + appearance_features = self.appearance_features[crop_ids] + colors_param = self.base_colors[crop_ids] + + camera_scale_fac = self._get_downscale_factor() + camera.rescale_output_resolution(1 / camera_scale_fac) + viewmat = get_viewmat(optimized_camera_to_world) + intrinsics = camera.get_intrinsics_matrices().to(self.device) + width, height = int(camera.width.item()), int(camera.height.item()) + self.last_size = (height, width) + + if self.config.output_depth_during_training or not self.training: + render_mode = "RGB+ED" + else: + render_mode = "RGB" + + colors = self._compute_colors(appearance_embed, use_cache) + if crop_ids is not None: + colors = colors[crop_ids] + if colors.shape[0] != appearance_features.shape[0]: + # safety fallback for stale eval cache + embed = appearance_embed.unsqueeze(0).expand(appearance_features.shape[0], -1) + colors = self.color_nn(embed, appearance_features).float() + if not self.training: + self._eval_cache["colors"] = None + + render, alpha, info = self._rasterize( + means=means, + quats=quats / quats.norm(dim=-1, keepdim=True), + scales=torch.exp(scales), + opacities=torch.sigmoid(opacities).squeeze(-1), + colors=colors, + viewmats=viewmat, + intrinsics=intrinsics, + width=width, + height=height, + render_mode=render_mode, + sh_degree=sh_degree_to_use, + ) + means2d, radii = self._resolve_means2d_and_radii(info) + if self.training and isinstance(means2d, torch.Tensor) and means2d.requires_grad: + means2d.retain_grad() + self.xys = means2d + self.radii = radii + alpha = alpha[:, ...] + + if self.bg_model is not None: + directions = normalize(camera.generate_rays(camera_indices=0, keep_shape=False).directions) + bg_sh = self._compute_bg_sh(appearance_embed, use_cache) + assert bg_sh is not None + background = spherical_harmonics( + degrees_to_use=bg_sh_degree_to_use, + coeffs=bg_sh.repeat(directions.shape[0], 1, 1), + dirs=directions, + ).view(1, height, width, 3) + else: + background = self._get_background_color().view(1, 1, 1, 3) + + rgb = torch.clamp(render[:, ..., :3] + (1 - alpha) * background, 0.0, 1.0) + camera.rescale_output_resolution(camera_scale_fac) + + if render_mode == "RGB+ED": + depth = render[:, ..., 3:4] + depth = torch.where(alpha > 0, depth, depth.detach().max()).squeeze(0) + else: + depth = None + + bg_out = background.squeeze(0) + return { + "rgb": rgb.squeeze(0), + "depth": depth, + "accumulation": alpha.squeeze(0), + "background": bg_out, + "base_colors": colors_param, + } + + def get_gt_img(self, image: torch.Tensor) -> torch.Tensor: + if image.dtype == torch.uint8: + image = image.float() / 255.0 + return self._downscale_if_required(image).to(self.device) + + def composite_with_background(self, image: torch.Tensor, background: torch.Tensor) -> torch.Tensor: + if image.shape[2] == 4: + alpha = image[..., -1:].repeat(1, 1, 3) + return alpha * image[..., :3] + (1 - alpha) * background + return image + + def get_metrics_dict(self, outputs, batch) -> Dict[str, torch.Tensor]: + gt_rgb = self.composite_with_background(self.get_gt_img(batch["image"]), outputs["background"]) + predicted_rgb = outputs["rgb"] + metrics = { + "psnr": self.psnr(predicted_rgb, gt_rgb), + "gaussian_count": torch.tensor(float(self.num_points), device=self.device), + } + self.camera_optimizer.get_metrics_dict(metrics) + return metrics + + def get_loss_dict(self, outputs, batch, metrics_dict=None) -> Dict[str, torch.Tensor]: + gt_img = self.composite_with_background(self.get_gt_img(batch["image"]), outputs["background"]) + pred_img = outputs["rgb"] + if "mask" in batch: + mask = self._downscale_if_required(batch["mask"]).to(self.device) + gt_img = gt_img * mask + pred_img = pred_img * mask + + l1_img = torch.abs(gt_img - pred_img) + if self.step >= self.config.start_robust_mask_at and self.config.enable_robust_mask: + robust_mask = self.robust_mask(l1_img) + gt_img = gt_img * robust_mask + pred_img = pred_img * robust_mask + l1 = (l1_img * robust_mask).mean() + else: + l1 = l1_img.mean() + + simloss = 1 - self.ssim(gt_img.permute(2, 0, 1)[None, ...], pred_img.permute(2, 0, 1)[None, ...]) + if self.config.use_scale_regularization and self.step % 10 == 0: + scale_exp = torch.exp(self.scales) + scale_reg = ( + torch.maximum( + scale_exp.amax(dim=-1) / scale_exp.amin(dim=-1), + torch.tensor(self.config.max_gauss_ratio, device=self.device), + ) + - self.config.max_gauss_ratio + ) + scale_reg = 0.1 * scale_reg.mean() + else: + scale_reg = torch.tensor(0.0, device=self.device) + + if self.config.enable_alpha_loss: + alpha_loss = torch.tensor(0.0, device=self.device) + background = outputs["background"] + alpha = outputs["accumulation"] + bg_mask = torch.abs(gt_img - background).mean(dim=-1, keepdim=True) < 0.003 + filt = 3 + window = (torch.ones((filt, filt), device=self.device).view(1, 1, filt, filt) / (filt * filt)) + bg_mask = ( + F.conv2d(bg_mask.float().unsqueeze(0).permute(0, 3, 1, 2), window, stride=1, padding="same") + .permute(0, 2, 3, 1) + .squeeze(0) + ) + alpha_mask = bg_mask > 0.6 + if torch.any(alpha_mask): + alpha_loss = alpha[alpha_mask].mean() * 0.15 + else: + alpha_loss = torch.tensor(0.0, device=self.device) + + loss_dict = { + "main_loss": (1 - self.config.ssim_lambda) * l1 + self.config.ssim_lambda * simloss, + "scale_reg": scale_reg, + "alpha_loss": alpha_loss, + } + if self.training: + self.camera_optimizer.get_loss_dict(loss_dict) + return loss_dict + + @torch.no_grad() + def get_outputs_for_camera(self, camera: Cameras, obb_box: Optional[OrientedBox] = None) -> Dict[str, torch.Tensor]: + assert camera is not None + self.set_crop(obb_box) + return self.get_outputs(camera.to(self.device)) # type: ignore[return-value] + + def get_image_metrics_and_images( + self, outputs: Dict[str, torch.Tensor], batch: Dict[str, torch.Tensor] + ) -> Tuple[Dict[str, float], Dict[str, torch.Tensor]]: + gt_rgb = self.composite_with_background(self.get_gt_img(batch["image"]), outputs["background"]) + predicted_rgb = outputs["rgb"] + combined_rgb = torch.cat([gt_rgb, predicted_rgb], dim=1) + if self.config.eval_right_half: + gt_rgb = gt_rgb[:, gt_rgb.shape[1] // 2 :, :] + predicted_rgb = predicted_rgb[:, predicted_rgb.shape[1] // 2 :, :] + + gt_metric = torch.moveaxis(gt_rgb, -1, 0)[None, ...] + pred_metric = torch.moveaxis(predicted_rgb, -1, 0)[None, ...] + psnr = self.psnr(gt_metric, pred_metric) + ssim = self.ssim(gt_metric, pred_metric) + lpips = self.lpips(gt_metric, pred_metric) + metrics = {"psnr": float(psnr.item()), "ssim": float(ssim), "lpips": float(lpips)} + return metrics, {"img": combined_rgb} + + @torch.no_grad() + def robust_mask(self, errors: torch.Tensor) -> torch.Tensor: + epsilon = 1e-3 + errors = errors.clone() + errors[: int(errors.shape[0] * self.config.never_mask_upper), :, :] = 0.0 + l1 = errors.mean() + if l1 > self.max_loss or self.step % self.config.robust_mask_reset_interval == 0: + self.max_loss = float(l1) + if l1 < self.min_loss: + self.min_loss = float(l1) + + mask_min, mask_max = self.config.robust_mask_percentage + mask_percentage = (float(l1) - self.min_loss) / ((self.max_loss - self.min_loss) + 1e-6) + mask_percentage = mask_percentage * (mask_max - mask_min) + mask_min + + errors_b = errors.view(1, errors.shape[0], errors.shape[1], errors.shape[2]) + error_per_pixel = torch.mean(errors_b, dim=-1, keepdim=True) + inlier_threshold = torch.quantile(error_per_pixel, 1 - mask_percentage) + is_inlier = (error_per_pixel <= inlier_threshold).float() + filt = 5 + window = (torch.ones((filt, filt), device=self.device).view(1, 1, filt, filt) / (filt * filt)) + has_inlier_neighbors = F.conv2d(is_inlier.permute(0, 3, 1, 2), window, stride=1, padding="same") + has_inlier_neighbors = has_inlier_neighbors.permute(0, 2, 3, 1) + has_inlier_neighbors = (has_inlier_neighbors > 0.4).float() + return ((has_inlier_neighbors + is_inlier > epsilon).float().view(errors.shape[0], errors.shape[1], 1)) + + @torch.no_grad() + def render_equirect(self, width: int, appearance_embed: Optional[torch.Tensor] = None) -> torch.Tensor: + height = width // 2 + fx = fy = torch.tensor(height, device=self.device) + cx = torch.tensor(width / 2, device=self.device) + cy = torch.tensor(height / 2, device=self.device) + from nerfstudio.cameras.cameras import CameraType + + c2w = torch.tensor( + [[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], + device=self.device, + dtype=torch.float32, + )[None, :3, :] + camera = Cameras( + fx=fx, + fy=fy, + cx=cx, + cy=cy, + camera_to_worlds=c2w, + camera_type=CameraType.EQUIRECTANGULAR, + ).to(self.device) + ray_bundle = camera.generate_rays(0, keep_shape=False, disable_distortion=True) + assert self.bg_model is not None + if appearance_embed is None: + appearance_embed = self.appearance_embeds.weight.mean(dim=0) + return self.bg_model(ray_bundle, appearance_embed).float().clamp(0, 1).reshape(height, width, 3) diff --git a/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model.py.tensorpatch b/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model.py.tensorpatch new file mode 100644 index 0000000000..fea3d8c0bf --- /dev/null +++ b/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model.py.tensorpatch @@ -0,0 +1,1435 @@ +# ruff: noqa: E741 +# Copyright 2022 the Regents of the University of California, Nerfstudio Team and contributors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Gaussian Splatting Model in the Wild implementation in nerfstudio. +https://kevinxu02.github.io/gsw.github.io/ +""" + +from gsplat.cuda._wrapper import spherical_harmonics +import math +from dataclasses import dataclass, field +from typing import Dict, List, Literal, Optional, Tuple, Type, Union +from nerfstudio.cameras.camera_utils import normalize +from splatfactow.splatfactow_field import BGField, SplatfactoWField + +import numpy as np +import torch +from torch import Tensor + +try: + from gsplat.rendering import rasterization +except ImportError: + print("Please install gsplat>=1.0.0") + +from pytorch_msssim import SSIM +from torch.nn import Parameter +import torch.nn.functional as F + + +from nerfstudio.cameras.camera_optimizers import CameraOptimizer, CameraOptimizerConfig +from nerfstudio.cameras.cameras import Cameras +from nerfstudio.data.scene_box import OrientedBox +from nerfstudio.engine.callbacks import ( + TrainingCallback, + TrainingCallbackAttributes, + TrainingCallbackLocation, +) +from nerfstudio.engine.optimizers import Optimizers +from nerfstudio.models.base_model import Model, ModelConfig +from nerfstudio.utils.colors import get_color +from nerfstudio.utils.misc import torch_compile +from nerfstudio.utils.rich_utils import CONSOLE + +def quat_to_rotmat(quats: Tensor) -> Tensor: + """Convert quaternion to rotation matrix.""" + quats = F.normalize(quats, p=2, dim=-1) + w, x, y, z = torch.unbind(quats, dim=-1) + R = torch.stack( + [ + 1 - 2 * (y**2 + z**2), + 2 * (x * y - w * z), + 2 * (x * z + w * y), + 2 * (x * y + w * z), + 1 - 2 * (x**2 + z**2), + 2 * (y * z - w * x), + 2 * (x * z - w * y), + 2 * (y * z + w * x), + 1 - 2 * (x**2 + y**2), + ], + dim=-1, + ) + return R.reshape(quats.shape[:-1] + (3, 3)) + +def random_quat_tensor(N): + """ + Defines a random quaternion tensor of shape (N, 4) + """ + u = torch.rand(N) + v = torch.rand(N) + w = torch.rand(N) + return torch.stack( + [ + torch.sqrt(1 - u) * torch.sin(2 * math.pi * v), + torch.sqrt(1 - u) * torch.cos(2 * math.pi * v), + torch.sqrt(u) * torch.sin(2 * math.pi * w), + torch.sqrt(u) * torch.cos(2 * math.pi * w), + ], + dim=-1, + ) + + +def RGB2SH(rgb): + """ + Converts from RGB values [0,1] to the 0th spherical harmonic coefficient + """ + C0 = 0.28209479177387814 + return (rgb - 0.5) / C0 + + +def SH2RGB(sh): + """ + Converts from the 0th spherical harmonic coefficient to RGB values [0,1] + """ + C0 = 0.28209479177387814 + return sh * C0 + 0.5 + + +def resize_image(image: torch.Tensor, d: int): + """ + Downscale images using the same 'area' method in opencv + + :param image shape [H, W, C] + :param d downscale factor (must be 2, 4, 8, etc.) + + return downscaled image in shape [H//d, W//d, C] + """ + import torch.nn.functional as tf + + image = image.to(torch.float32) + weight = (1.0 / (d * d)) * torch.ones( + (1, 1, d, d), dtype=torch.float32, device=image.device + ) + return ( + tf.conv2d(image.permute(2, 0, 1)[:, None, ...], weight, stride=d) + .squeeze(1) + .permute(1, 2, 0) + ) + + +@torch_compile() +def get_viewmat(optimized_camera_to_world): + """ + function that converts c2w to gsplat world2camera matrix, using compile for some speed + """ + R = optimized_camera_to_world[:, :3, :3] # 3 x 3 + T = optimized_camera_to_world[:, :3, 3:4] # 3 x 1 + # flip the z and y axes to align with gsplat conventions + R = R * torch.tensor([[[1, -1, -1]]], device=R.device, dtype=R.dtype) + # analytic matrix inverse to get world2camera matrix + R_inv = R.transpose(1, 2) + T_inv = -torch.bmm(R_inv, T) + viewmat = torch.zeros(R.shape[0], 4, 4, device=R.device, dtype=R.dtype) + viewmat[:, 3, 3] = 1.0 # homogenous + viewmat[:, :3, :3] = R_inv + viewmat[:, :3, 3:4] = T_inv + return viewmat + + +@dataclass +class SplatfactoWModelConfig(ModelConfig): + """Splatfacto Model Config, nerfstudio's implementation of Gaussian Splatting""" + + _target: Type = field(default_factory=lambda: SplatfactoWModel) + warmup_length: int = 1000 + """period of steps where refinement is turned off""" + refine_every: int = 100 + """period of steps where gaussians are culled and densified""" + resolution_schedule: int = 3000 + """training starts at 1/d resolution, every n steps this is doubled""" + background_color: Literal["random", "black", "white"] = "random" + """Whether to randomize the background color.""" + num_downscales: int = 2 + """at the beginning, resolution is 1/2^d, where d is this number""" + cull_alpha_thresh: float = 0.1 + """threshold of opacity for culling gaussians. One can set it to a lower value (e.g. 0.005) for higher quality.""" + cull_scale_thresh: float = 0.5 + """threshold of scale for culling huge gaussians""" + continue_cull_post_densification: bool = True + """If True, continue to cull gaussians post refinement""" + reset_alpha_every: int = 25 + """Every this many refinement steps, reset the alpha""" + densify_grad_thresh: float = 0.0008 + """threshold of positional gradient norm for densifying gaussians""" + densify_size_thresh: float = 0.01 + """below this size, gaussians are *duplicated*, otherwise split""" + n_split_samples: int = 2 + """number of samples to split gaussians into""" + cull_screen_size: float = 0.15 + """if a gaussian is more than this percent of screen space, cull it""" + split_screen_size: float = 0.05 + """if a gaussian is more than this percent of screen space, split it""" + stop_screen_size_at: int = 15000 + """stop culling/splitting at this step WRT screen size of gaussians""" + random_init: bool = False + """whether to initialize the positions uniformly randomly (not SFM points)""" + num_random: int = 50000 + """Number of gaussians to initialize if random init is used""" + random_scale: float = 10.0 + "Size of the cube to initialize random gaussians within" + ssim_lambda: float = 0.2 + """weight of ssim loss""" + stop_split_at: int = 20000 + """stop splitting at this step""" + use_scale_regularization: bool = False + """If enabled, a scale regularization introduced in PhysGauss (https://xpandora.github.io/PhysGaussian/) is used for reducing huge spikey gaussians.""" + max_gauss_ratio: float = 10.0 + """threshold of ratio of gaussian max to min scale before applying regularization + loss from the PhysGaussian paper + """ + output_depth_during_training: bool = False + """If True, output depth during training. Otherwise, only output depth during evaluation.""" + rasterize_mode: Literal["classic", "antialiased"] = "antialiased" + """ + Classic mode of rendering will use the EWA volume splatting with a [0.3, 0.3] screen space blurring kernel. This + approach is however not suitable to render tiny gaussians at higher or lower resolution than the captured, which + results "aliasing-like" artifacts. The antialiased mode overcomes this limitation by calculating compensation factors + and apply them to the opacities of gaussians to preserve the total integrated density of splats. + + However, PLY exported with antialiased rasterize mode is not compatible with classic mode. Thus many web viewers that + were implemented for classic mode can not render antialiased mode PLY properly without modifications. + """ + camera_optimizer: CameraOptimizerConfig = field( + default_factory=lambda: CameraOptimizerConfig(mode="off") + ) + """Config of the camera optimizer to use""" + enable_bg_model: bool = True + """Whether to enable the 2d background model""" + bg_num_layers: int = 3 + """Number of layers in the background model""" + bg_layer_width: int = 128 + """Width of each layer in the background model""" + implementation: Literal["tcnn", "torch"] = "torch" + """Implementation of the models""" + appearance_embed_dim: int = 48 + """Dimension of the appearance embedding, if 0, no appearance embedding is used""" + app_num_layers: int = 3 + """Number of layers in the appearance model""" + app_layer_width: int = 256 + """Width of each layer in the appearance model""" + enable_alpha_loss: bool = True + """Whether to enable the alpha loss for punishing gaussians from occupying background space, this also works with pure color background (i.e. white for overexposed skys)""" + appearance_features_dim: int = 72 + """Dimension of the appearance feature""" + enable_robust_mask: bool = True + """Whether to enable robust mask for calculating the loss""" + robust_mask_percentage: tuple = (0.0, 0.40) + """The percentage of the entire image to mask out for robust loss calculation""" + robust_mask_reset_interval: int = 6000 + """The interval to reset the mask""" + never_mask_upper: float = 0.4 + """Whether to mask out the upper part of the image, which is usually the sky""" + start_robust_mask_at: int = 6000 + """The step to start masking""" + sh_degree_interval: int = 2000 + """The interval to increase the SH degree""" + sh_degree: int = 3 + """The degree of SH to use for the color field""" + bg_sh_degree: int = 4 + """The degree of SH to use for the background model""" + use_avg_appearance: bool = False + """Whether to use the average appearance embedding or 0-th for evaluation""" + eval_right_half: bool = False + """Whether to use the right half of the image for evluation""" + + +class SplatfactoWModel(Model): + """Nerfstudio's implementation of Gaussian Splatting + + Args: + config: Splatfacto configuration to instantiate model + """ + + config: SplatfactoWModelConfig + + def __init__( + self, + *args, + seed_points: Optional[Tuple[torch.Tensor, torch.Tensor]] = None, + **kwargs, + ): + self.seed_points = seed_points + super().__init__(*args, **kwargs) + + def populate_modules(self): + if self.seed_points is not None and not self.config.random_init: + means = torch.nn.Parameter(self.seed_points[0]) # (Location, Color) + else: + means = torch.nn.Parameter( + (torch.rand((self.config.num_random, 3)) - 0.5) + * self.config.random_scale + ) + self.xys_grad_norm = None + self.max_2Dsize = None + distances, _ = self.k_nearest_sklearn(means.data, 3) + distances = torch.from_numpy(distances) + # find the average of the three nearest neighbors for each point and use that as the scale + avg_dist = distances.mean(dim=-1, keepdim=True) + scales = torch.nn.Parameter(torch.log(avg_dist.repeat(1, 3))) + num_points = means.shape[0] + quats = torch.nn.Parameter(random_quat_tensor(num_points)) + appearance_features = torch.nn.Parameter( + torch.zeros((num_points, self.config.appearance_features_dim)) + .float() + .cuda() + ) + if ( + self.seed_points is not None + # We can have colors without points. + and self.seed_points[1].shape[0] > 0 + ): + # colors = torch.logit(self.seed_points[1] / 255, eps=1e-10).float().cuda() + # rgb values of the seed points are in [0, 1] range + colors = torch.nn.Parameter(self.seed_points[1] / 255).float().cuda() + else: + colors = torch.nn.Parameter(torch.zeros((num_points, 3))).cuda() + + opacities = torch.nn.Parameter(torch.logit(0.1 * torch.ones(num_points, 1))) + self.gauss_params = torch.nn.ParameterDict( + { + "means": means, + "scales": scales, + "quats": quats, + "appearance_features": appearance_features, + "colors": colors, + "opacities": opacities, + } + ) + + self.camera_optimizer: CameraOptimizer = self.config.camera_optimizer.setup( + num_cameras=self.num_train_data, device="cpu" + ) + + # metrics + from torchmetrics.image import PeakSignalNoiseRatio + from torchmetrics.image.lpip import LearnedPerceptualImagePatchSimilarity + + self.max_loss = 0.0 + self.min_loss = 1e10 + + self.psnr = PeakSignalNoiseRatio(data_range=1.0) + self.ssim = SSIM(data_range=1.0, size_average=True, channel=3) + self.lpips = LearnedPerceptualImagePatchSimilarity(normalize=True) + self.step = 0 + + self.crop_box: Optional[OrientedBox] = None + if self.config.background_color == "random": + self.background_color = torch.tensor( + [0.1490, 0.1647, 0.2157] + ) # This color is the same as the default background color in Viser. This would only affect the background color when rendering. + else: + self.background_color = get_color(self.config.background_color) + + assert self.config.appearance_embed_dim > 0 + self.appearance_embeds = torch.nn.Embedding( + self.num_train_data, self.config.appearance_embed_dim + ) + + if self.config.enable_bg_model: + self.bg_model = BGField( + appearance_embedding_dim=self.config.appearance_embed_dim, + implementation=self.config.implementation, + sh_levels=self.config.bg_sh_degree, + num_layers=self.config.bg_num_layers, + layer_width=self.config.bg_layer_width, + ) + else: + self.bg_model = None + + self.color_nn = SplatfactoWField( + appearance_embed_dim=self.config.appearance_embed_dim, + appearance_features_dim=self.config.appearance_features_dim, + implementation=self.config.implementation, + sh_levels=self.config.sh_degree, + num_layers=self.config.app_num_layers, + layer_width=self.config.app_layer_width, + ) + + self.cached_colors = None + self.cached_bg_sh = None + self.last_cam_idx = None + self.cached_dirs = {} + + self.camera_idx = 0 + + # def setup_shs(self, cam_idx: int): + # appearance_features = self.gauss_params["appearance_features"] + # appearance_embed = self.appearance_embeds( + # torch.tensor(cam_idx, device=self.device) + # ) + # self.shs_0 =self.color_nn.shs_0( + # appearance_embed=appearance_embed.repeat(appearance_features.shape[0], 1), + # appearance_features=appearance_features, + # ) + # self.shs_rest = self.color_nn.shs_rest( + # appearance_embed=appearance_embed.repeat(appearance_features.shape[0], 1), + # appearance_features=appearance_features, + # ) + + def set_camera_idx(self, cam_idx: int): + self.camera_idx = cam_idx + + @property + def shs_0(self): + appearance_features = self.gauss_params["appearance_features"] + appearance_embed = self.appearance_embeds( + torch.tensor(self.camera_idx, device=self.device) + ) + return self.color_nn.shs_0( + appearance_embed=appearance_embed.repeat(appearance_features.shape[0], 1), + appearance_features=appearance_features, + ) + + @property + def shs_rest(self): + appearance_features = self.gauss_params["appearance_features"] + appearance_embed = self.appearance_embeds( + torch.tensor(self.camera_idx, device=self.device) + ) + return self.color_nn.shs_rest( + appearance_embed=appearance_embed.repeat(appearance_features.shape[0], 1), + appearance_features=appearance_features, + ) + + @property + def num_points(self): + return self.means.shape[0] + + @property + def means(self): + return self.gauss_params["means"] + + @property + def scales(self): + return self.gauss_params["scales"] + + @property + def quats(self): + return self.gauss_params["quats"] + + @property + def appearance_features(self): + return self.gauss_params["appearance_features"] + + @property + def base_colors(self): + return self.gauss_params["colors"] + + # @property + # def features_rest(self): + # return self.gauss_params["features_rest"] + + @property + def opacities(self): + return self.gauss_params["opacities"] + + def load_state_dict(self, dict, **kwargs): # type: ignore + # resize the parameters to match the new number of points + self.step = 30000 + if "means" in dict: + # For backwards compatibility, we remap the names of parameters from + # means->gauss_params.means since old checkpoints have that format + for p in [ + "means", + "scales", + "quats", + "appearance_features", + "opacities", + "colors", + ]: + dict[f"gauss_params.{p}"] = dict[p] + newp = dict["gauss_params.means"].shape[0] + for name, param in self.gauss_params.items(): + old_shape = param.shape + new_shape = (newp,) + old_shape[1:] + self.gauss_params[name] = torch.nn.Parameter( + torch.zeros(new_shape, device=self.device) + ) + super().load_state_dict(dict, **kwargs) + + def k_nearest_sklearn(self, x: torch.Tensor, k: int): + """ + Find k-nearest neighbors using sklearn's NearestNeighbors. + x: The data tensor of shape [num_samples, num_features] + k: The number of neighbors to retrieve + """ + # Convert tensor to numpy array + x_np = x.cpu().numpy() + + # Build the nearest neighbors model + from sklearn.neighbors import NearestNeighbors + + nn_model = NearestNeighbors( + n_neighbors=k + 1, algorithm="auto", metric="euclidean" + ).fit(x_np) + + # Find the k-nearest neighbors + distances, indices = nn_model.kneighbors(x_np) + + # Exclude the point itself from the result and return + return distances[:, 1:].astype(np.float32), indices[:, 1:].astype(np.float32) + + def remove_from_optim(self, optimizer, deleted_mask, new_params): + """removes the deleted_mask from the optimizer provided""" + assert len(new_params) == 1 + # assert isinstance(optimizer, torch.optim.Adam), "Only works with Adam" + + param = optimizer.param_groups[0]["params"][0] + param_state = optimizer.state[param] + del optimizer.state[param] + + # Modify the state directly without deleting and reassigning. + if "exp_avg" in param_state: + param_state["exp_avg"] = param_state["exp_avg"][~deleted_mask] + param_state["exp_avg_sq"] = param_state["exp_avg_sq"][~deleted_mask] + + # Update the parameter in the optimizer's param group. + del optimizer.param_groups[0]["params"][0] + del optimizer.param_groups[0]["params"] + optimizer.param_groups[0]["params"] = new_params + optimizer.state[new_params[0]] = param_state + + def remove_from_all_optim(self, optimizers, deleted_mask): + param_groups = self.get_gaussian_param_groups() + for group, param in param_groups.items(): + self.remove_from_optim(optimizers.optimizers[group], deleted_mask, param) + torch.cuda.empty_cache() + + def dup_in_optim(self, optimizer, dup_mask, new_params, n=2): + """adds the parameters to the optimizer""" + param = optimizer.param_groups[0]["params"][0] + param_state = optimizer.state[param] + if "exp_avg" in param_state: + repeat_dims = (n,) + tuple( + 1 for _ in range(param_state["exp_avg"].dim() - 1) + ) + param_state["exp_avg"] = torch.cat( + [ + param_state["exp_avg"], + torch.zeros_like(param_state["exp_avg"][dup_mask.squeeze()]).repeat( + *repeat_dims + ), + ], + dim=0, + ) + param_state["exp_avg_sq"] = torch.cat( + [ + param_state["exp_avg_sq"], + torch.zeros_like( + param_state["exp_avg_sq"][dup_mask.squeeze()] + ).repeat(*repeat_dims), + ], + dim=0, + ) + del optimizer.state[param] + optimizer.state[new_params[0]] = param_state + optimizer.param_groups[0]["params"] = new_params + del param + + def dup_in_all_optim(self, optimizers, dup_mask, n): + param_groups = self.get_gaussian_param_groups() + for group, param in param_groups.items(): + self.dup_in_optim(optimizers.optimizers[group], dup_mask, param, n) + + def _collapse_radii_to_pointwise(self, radii: torch.Tensor) -> torch.Tensor: + """Return one scalar radius per gaussian across gsplat versions. + + Older gsplat versions returned radii shaped like ``[N]`` or ``[N, 1]``. + Newer versions may return ``[N, 2]`` (per-axis image-space radii). For + densification and visibility bookkeeping we only need a single scalar per + gaussian, so we conservatively take the maximum positive radius across the + trailing dimensions. + """ + radii = radii.to(dtype=torch.float32) + if radii.ndim <= 1: + return radii.reshape(-1) + return radii.reshape(radii.shape[0], -1).amax(dim=-1) + + def _get_visible_mask_and_radii(self) -> Tuple[torch.Tensor, torch.Tensor]: + """Build a per-gaussian visibility mask and scalar radii. + + This is backward compatible with gsplat variants that expose radii as + ``[N]``, ``[N, 1]`` or ``[N, 2]``. + """ + radii_1d = self._collapse_radii_to_pointwise(self.radii) + visible_mask = radii_1d > 0 + return visible_mask.reshape(-1), radii_1d.reshape(-1) + + def after_train(self, step: int): + assert step == self.step + # to save some training time, we no longer need to update those stats post refinement + if self.step >= self.config.stop_split_at: + return + with torch.no_grad(): + # keep track of a moving average of grad norms + visible_mask, radii_1d = self._get_visible_mask_and_radii() + grads_xy = self.xys.absgrad[0] # type: ignore[index] + if visible_mask.shape[0] != grads_xy.shape[0]: + raise RuntimeError( + "Incompatible gsplat metadata shapes: " + f"visible mask has shape {tuple(visible_mask.shape)} while " + f"means2d gradients have shape {tuple(grads_xy.shape)}." + ) + grads = grads_xy[visible_mask].norm(dim=-1) + # print(f"grad norm min {grads.min().item()} max {grads.max().item()} mean {grads.mean().item()} size {grads.shape}") + if self.xys_grad_norm is None: + self.xys_grad_norm = torch.zeros( + self.num_points, device=self.device, dtype=torch.float32 + ) + self.vis_counts = torch.ones( + self.num_points, device=self.device, dtype=torch.float32 + ) + assert self.vis_counts is not None + self.vis_counts[visible_mask] += 1 + self.xys_grad_norm[visible_mask] += grads + # update the max screen size, as a ratio of number of pixels + if self.max_2Dsize is None: + self.max_2Dsize = torch.zeros_like(radii_1d, dtype=torch.float32) + newradii = radii_1d.detach()[visible_mask] + self.max_2Dsize[visible_mask] = torch.maximum( + self.max_2Dsize[visible_mask], + newradii / float(max(self.last_size[0], self.last_size[1])), + ) + + def set_crop(self, crop_box: Optional[OrientedBox]): + self.crop_box = crop_box + + def set_background(self, background_color: torch.Tensor): + assert background_color.shape == (3,) + self.background_color = background_color + + def refinement_after(self, optimizers: Optimizers, step): + assert step == self.step + if self.step <= self.config.warmup_length: + return + with torch.no_grad(): + # Offset all the opacity reset logic by refine_every so that we don't + # save checkpoints right when the opacity is reset (saves every 2k) + # then cull + # only split/cull if we've seen every image since opacity reset + reset_interval = self.config.reset_alpha_every * self.config.refine_every + do_densification = ( + self.step < self.config.stop_split_at + and self.step % reset_interval + > self.num_train_data + self.config.refine_every + ) + if do_densification: + # then we densify + assert ( + self.xys_grad_norm is not None + and self.vis_counts is not None + and self.max_2Dsize is not None + ) + avg_grad_norm = ( + (self.xys_grad_norm / self.vis_counts) + * 0.5 + * max(self.last_size[0], self.last_size[1]) + ) + high_grads = (avg_grad_norm > self.config.densify_grad_thresh).squeeze() + splits = ( + self.scales.exp().max(dim=-1).values + > self.config.densify_size_thresh + ).squeeze() + if self.step < self.config.stop_screen_size_at: + splits |= ( + self.max_2Dsize > self.config.split_screen_size + ).squeeze() + splits &= high_grads + nsamps = self.config.n_split_samples + split_params = self.split_gaussians(splits, nsamps) + + dups = ( + self.scales.exp().max(dim=-1).values + <= self.config.densify_size_thresh + ).squeeze() + dups &= high_grads + dup_params = self.dup_gaussians(dups) + for name, param in self.gauss_params.items(): + self.gauss_params[name] = torch.nn.Parameter( + torch.cat( + [param.detach(), split_params[name], dup_params[name]], + dim=0, + ) + ) + # append zeros to the max_2Dsize tensor + self.max_2Dsize = torch.cat( + [ + self.max_2Dsize, + torch.zeros_like(split_params["scales"][:, 0]), + torch.zeros_like(dup_params["scales"][:, 0]), + ], + dim=0, + ) + + split_idcs = torch.where(splits)[0] + self.dup_in_all_optim(optimizers, split_idcs, nsamps) + + dup_idcs = torch.where(dups)[0] + self.dup_in_all_optim(optimizers, dup_idcs, 1) + + # After a guassian is split into two new gaussians, the original one should also be pruned. + splits_mask = torch.cat( + ( + splits, + torch.zeros( + nsamps * splits.sum() + dups.sum(), + device=self.device, + dtype=torch.bool, + ), + ) + ) + + deleted_mask = self.cull_gaussians(splits_mask) + elif ( + self.step >= self.config.stop_split_at + and self.config.continue_cull_post_densification + ): + deleted_mask = self.cull_gaussians() + else: + # if we donot allow culling post refinement, no more gaussians will be pruned. + deleted_mask = None + + if deleted_mask is not None: + self.remove_from_all_optim(optimizers, deleted_mask) + + if ( + self.step < self.config.stop_split_at + and self.step % reset_interval == self.config.refine_every + ): + # Reset value is set to be twice of the cull_alpha_thresh + reset_value = self.config.cull_alpha_thresh * 2.0 + self.opacities.data = torch.clamp( + self.opacities.data, + max=torch.logit( + torch.tensor(reset_value, device=self.device) + ).item(), + ) + # reset the exp of optimizer + optim = optimizers.optimizers["opacities"] + param = optim.param_groups[0]["params"][0] + param_state = optim.state[param] + param_state["exp_avg"] = torch.zeros_like(param_state["exp_avg"]) + param_state["exp_avg_sq"] = torch.zeros_like(param_state["exp_avg_sq"]) + + self.xys_grad_norm = None + self.vis_counts = None + self.max_2Dsize = None + + def cull_gaussians(self, extra_cull_mask: Optional[torch.Tensor] = None): + """ + This function deletes gaussians with under a certain opacity threshold + extra_cull_mask: a mask indicates extra gaussians to cull besides existing culling criterion + """ + n_bef = self.num_points + # cull transparent ones + culls = ( + torch.sigmoid(self.opacities) < self.config.cull_alpha_thresh + ).squeeze() + below_alpha_count = torch.sum(culls).item() + toobigs_count = 0 + if extra_cull_mask is not None: + culls = culls | extra_cull_mask + if self.step > self.config.refine_every * self.config.reset_alpha_every: + # cull huge ones + toobigs = ( + torch.exp(self.scales).max(dim=-1).values + > self.config.cull_scale_thresh + ).squeeze() + if self.step < self.config.stop_screen_size_at: + # cull big screen space + if self.max_2Dsize is not None: + toobigs = ( + toobigs + | (self.max_2Dsize > self.config.cull_screen_size).squeeze() + ) + culls = culls | toobigs + toobigs_count = torch.sum(toobigs).item() + for name, param in self.gauss_params.items(): + self.gauss_params[name] = torch.nn.Parameter(param[~culls]) + + CONSOLE.log( + f"Culled {n_bef - self.num_points} gaussians " + f"({below_alpha_count} below alpha thresh, {toobigs_count} too bigs, {self.num_points} remaining)" + ) + + return culls + + def split_gaussians(self, split_mask, samps): + """ + This function splits gaussians that are too large + """ + n_splits = split_mask.sum().item() + CONSOLE.log( + f"Splitting {split_mask.sum().item()/self.num_points} gaussians: {n_splits}/{self.num_points}" + ) + centered_samples = torch.randn( + (samps * n_splits, 3), device=self.device + ) # Nx3 of axis-aligned scales + scaled_samples = ( + torch.exp(self.scales[split_mask].repeat(samps, 1)) * centered_samples + ) # how these scales are rotated + quats = self.quats[split_mask] / self.quats[split_mask].norm( + dim=-1, keepdim=True + ) # normalize them first + rots = quat_to_rotmat(quats.repeat(samps, 1)) # how these scales are rotated + rotated_samples = torch.bmm(rots, scaled_samples[..., None]).squeeze() + new_means = rotated_samples + self.means[split_mask].repeat(samps, 1) + # step 2, sample new colors + new_appearance_features = self.appearance_features[split_mask].repeat(samps, 1) + new_colors = self.base_colors[split_mask].repeat(samps, 1) + # step 3, sample new opacities + new_opacities = self.opacities[split_mask].repeat(samps, 1) + # step 4, sample new scales + size_fac = 1.6 + new_scales = torch.log(torch.exp(self.scales[split_mask]) / size_fac).repeat( + samps, 1 + ) + self.scales[split_mask] = torch.log( + torch.exp(self.scales[split_mask]) / size_fac + ) + # step 5, sample new quats + new_quats = self.quats[split_mask].repeat(samps, 1) + out = { + "means": new_means, + "appearance_features": new_appearance_features, + "colors": new_colors, + "opacities": new_opacities, + "scales": new_scales, + "quats": new_quats, + } + for name, param in self.gauss_params.items(): + if name not in out: + out[name] = param[split_mask].repeat(samps, 1) + return out + + def dup_gaussians(self, dup_mask): + """ + This function duplicates gaussians that are too small + """ + n_dups = dup_mask.sum().item() + CONSOLE.log( + f"Duplicating {dup_mask.sum().item()/self.num_points} gaussians: {n_dups}/{self.num_points}" + ) + new_dups = {} + for name, param in self.gauss_params.items(): + new_dups[name] = param[dup_mask] + return new_dups + + def get_training_callbacks( + self, training_callback_attributes: TrainingCallbackAttributes + ) -> List[TrainingCallback]: + cbs = [] + cbs.append( + TrainingCallback( + [TrainingCallbackLocation.BEFORE_TRAIN_ITERATION], self.step_cb + ) + ) + # The order of these matters + cbs.append( + TrainingCallback( + [TrainingCallbackLocation.AFTER_TRAIN_ITERATION], + self.after_train, + ) + ) + cbs.append( + TrainingCallback( + [TrainingCallbackLocation.AFTER_TRAIN_ITERATION], + self.refinement_after, + update_every_num_iters=self.config.refine_every, + args=[training_callback_attributes.optimizers], + ) + ) + return cbs + + def step_cb(self, step): + self.step = step + + def get_gaussian_param_groups(self) -> Dict[str, List[Parameter]]: + # Here we explicitly use the means, scales as parameters so that the user can override this function and + # specify more if they want to add more optimizable params to gaussians. + return { + name: [self.gauss_params[name]] + for name in ["means", "scales", "quats", "appearance_features", "opacities"] + } + + def get_param_groups(self) -> Dict[str, List[Parameter]]: + """Obtain the parameter groups for the optimizers + + Returns: + Mapping of different parameter groups + """ + gps = self.get_gaussian_param_groups() + self.camera_optimizer.get_param_groups(param_groups=gps) + if self.config.enable_bg_model: + assert self.bg_model is not None + gps["field_background_encoder"] = list(self.bg_model.encoder.parameters()) + gps["field_background_base"] = list(self.bg_model.sh_base_head.parameters()) + gps["field_background_rest"] = list(self.bg_model.sh_rest_head.parameters()) + assert self.color_nn is not None + assert self.appearance_embeds is not None + gps["appearance_embed"] = list(self.appearance_embeds.parameters()) + gps["appearance_model_encoder"] = list(self.color_nn.encoder.parameters()) + gps["appearance_model_base"] = list(self.color_nn.sh_base_head.parameters()) + gps["appearance_model_rest"] = list(self.color_nn.sh_rest_head.parameters()) + + return gps + + def _get_downscale_factor(self): + if self.training: + return 2 ** max( + ( + self.config.num_downscales + - self.step // self.config.resolution_schedule + ), + 0, + ) + else: + return 1 + + def _downscale_if_required(self, image): + d = self._get_downscale_factor() + if d > 1: + return resize_image(image, d) + return image + + @staticmethod + def get_empty_outputs( + width: int, height: int, background: torch.Tensor + ) -> Dict[str, Union[torch.Tensor, List]]: + rgb = background.repeat(height, width, 1) + depth = background.new_ones(*rgb.shape[:2], 1) * 10 + accumulation = background.new_zeros(*rgb.shape[:2], 1) + return { + "rgb": rgb, + "depth": depth, + "accumulation": accumulation, + "background": background, + } + + def _get_background_color(self): + if self.config.background_color == "random": + if self.training: + background = torch.rand(3, device=self.device) + else: + background = self.background_color.to(self.device) + elif self.config.background_color == "white": + background = torch.ones(3, device=self.device) + elif self.config.background_color == "black": + background = torch.zeros(3, device=self.device) + else: + raise ValueError(f"Unknown background color {self.config.background_color}") + return background + + def get_outputs(self, camera: Cameras) -> Dict[str, Union[torch.Tensor, List]]: + """Takes in a Ray Bundle and returns a dictionary of outputs. + + Args: + ray_bundle: Input bundle of rays. This raybundle should have all the + needed information to compute the outputs. + + Returns: + Outputs of model. (ie. rendered colors) + """ + if not isinstance(camera, Cameras): + print("Called get_outputs with not a camera") + return {} + + if self.config.sh_degree > 0: + sh_degree_to_use = min( + self.step // self.config.sh_degree_interval, self.config.sh_degree + ) + bg_sh_degree_to_use = min( + self.step // (self.config.sh_degree_interval // 2), + self.config.bg_sh_degree, + ) + + # get the appearance embedding + use_cached_sh = False + if camera.metadata is not None and "cam_idx" in camera.metadata: + cam_idx = camera.metadata["cam_idx"] + if self.last_cam_idx is not None and not self.training: + use_cached_sh = cam_idx == self.last_cam_idx + if cam_idx != self.last_cam_idx: + CONSOLE.log("Current camera idx is", cam_idx) + self.last_cam_idx = cam_idx + appearance_embed = self.appearance_embeds( + torch.tensor(cam_idx, device=self.device) + ) + else: + if self.config.use_avg_appearance: + # calculate the average appearance embedding + appearance_embed = self.appearance_embeds.weight.mean(dim=0) + else: + appearance_embed = self.appearance_embeds( + torch.tensor(0, device=self.device) + ) + + if self.training: + assert camera.shape[0] == 1, "Only one camera at a time" + optimized_camera_to_world = self.camera_optimizer.apply_to_camera(camera) + else: + optimized_camera_to_world = camera.camera_to_worlds + + camera_scale_fac = self._get_downscale_factor() + camera.rescale_output_resolution(1 / camera_scale_fac) + viewmat = get_viewmat(optimized_camera_to_world) + W, H = int(camera.width.item()), int(camera.height.item()) + self.last_size = (H, W) + + opacities = self.opacities + means = self.means + appearance_features = self.appearance_features + scales = self.scales + quats = self.quats + # base_colors = self.base_colors + + BLOCK_WIDTH = ( + 16 # this controls the tile size of rasterization, 16 is a good default + ) + K = camera.get_intrinsics_matrices().cuda() + if self.config.rasterize_mode not in ["antialiased", "classic"]: + raise ValueError("Unknown rasterize_mode: %s", self.config.rasterize_mode) + + if self.config.output_depth_during_training or not self.training: + render_mode = "RGB+ED" + else: + render_mode = "RGB" + + if use_cached_sh and self.cached_colors is not None: + colors = self.cached_colors + else: + colors = self.color_nn( + appearance_embed.repeat(appearance_features.shape[0], 1), + appearance_features, + ).float() + self.cached_colors = colors + + render, alpha, info = rasterization( + means=means, + quats=quats / quats.norm(dim=-1, keepdim=True), + scales=torch.exp(scales), + opacities=torch.sigmoid(opacities).squeeze(-1), + colors=colors, + viewmats=viewmat, # [1, 4, 4] + Ks=K, # [1, 3, 3] + width=W, + height=H, + tile_size=BLOCK_WIDTH, + packed=False, + near_plane=0.01, + far_plane=1e10, + render_mode=render_mode, + sh_degree=sh_degree_to_use, + sparse_grad=False, + absgrad=True, + rasterize_mode=self.config.rasterize_mode, + # set some threshold to disregrad small gaussians for faster rendering. + # radius_clip=3.0, + ) + if self.training and info["means2d"].requires_grad: + info["means2d"].retain_grad() + self.xys = info["means2d"] # [1, N, 2] + self.radii = info["radii"][0] # [N] + alpha = alpha[:, ...] + + # background + + if self.config.enable_bg_model: + # if ( + # self.step > self.config.num_downscales * self.config.resolution_schedule + # and self.training + # ): + # # cache directions in training, hope this won't cause memory issue + # if self.last_cam_idx not in self.cached_dirs: + # directions = normalize( + # camera.generate_rays( + # camera_indices=0, keep_shape=False + # ).directions + # ).pin_memory() + # self.cached_dirs[self.last_cam_idx] = directions + # else: + # directions = self.cached_dirs[self.last_cam_idx] + + # else: + directions = normalize( + camera.generate_rays(camera_indices=0, keep_shape=False).directions + ) + + if use_cached_sh and not self.training and self.cached_bg_sh is not None: + bg_sh_coeffs = self.cached_bg_sh + else: + bg_sh_coeffs = self.bg_model.get_sh_coeffs( + appearance_embedding=appearance_embed + ) + self.cached_bg_sh = bg_sh_coeffs + + background = spherical_harmonics( + degrees_to_use=bg_sh_degree_to_use, + coeffs=bg_sh_coeffs.repeat(directions.shape[0], 1, 1), + dirs=directions, + ) + background = background.view(1, H, W, 3) + else: + background = self._get_background_color().view(1, 1, 1, 3) + + rgb = render[:, ..., :3] + (1 - alpha) * background + + camera.rescale_output_resolution(camera_scale_fac) # type: ignore + rgb = torch.clamp(rgb, 0.0, 1.0) + + # depth image + if render_mode == "RGB+ED": + depth_im = render[:, ..., 3:4] + depth_im = torch.where( + alpha > 0, depth_im, depth_im.detach().max() + ).squeeze(0) + else: + depth_im = None + + if background.shape[0] == 3: + background = background.expand(H, W, 3) + + return { + "rgb": rgb.squeeze(0), # type: ignore + "depth": depth_im, # type: ignore + "accumulation": alpha.squeeze(0), # type: ignore + "background": background.squeeze(0), # type: ignore + } # type: ignore + + def get_gt_img(self, image: torch.Tensor): + """Compute groundtruth image with iteration dependent downscale factor for evaluation purpose + + Args: + image: tensor.Tensor in type uint8 or float32 + """ + if image.dtype == torch.uint8: + image = image.float() / 255.0 + gt_img = self._downscale_if_required(image) + return gt_img.to(self.device) + + def composite_with_background(self, image, background) -> torch.Tensor: + """Composite the ground truth image with a background color when it has an alpha channel. + + Args: + image: the image to composite + background: the background color + """ + if image.shape[2] == 4: + alpha = image[..., -1].unsqueeze(-1).repeat((1, 1, 3)) + return alpha * image[..., :3] + (1 - alpha) * background + else: + return image + + def get_metrics_dict(self, outputs, batch) -> Dict[str, torch.Tensor]: + """Compute and returns metrics. + + Args: + outputs: the output to compute loss dict to + batch: ground truth batch corresponding to outputs + """ + gt_rgb = self.composite_with_background( + self.get_gt_img(batch["image"]), outputs["background"] + ) + metrics_dict = {} + predicted_rgb = outputs["rgb"] + metrics_dict["psnr"] = self.psnr(predicted_rgb, gt_rgb) + + metrics_dict["gaussian_count"] = self.num_points + + self.camera_optimizer.get_metrics_dict(metrics_dict) + return metrics_dict + + def get_loss_dict( + self, outputs, batch, metrics_dict=None + ) -> Dict[str, torch.Tensor]: + """Computes and returns the losses dict. + + Args: + outputs: the output to compute loss dict to + batch: ground truth batch corresponding to outputs + metrics_dict: dictionary of metrics, some of which we can use for loss + """ + gt_img = self.composite_with_background( + self.get_gt_img(batch["image"]), outputs["background"] + ) + pred_img = outputs["rgb"] + + # Set masked part of both ground-truth and rendered image to black. + # This is a little bit sketchy for the SSIM loss. + if "mask" in batch: + # batch["mask"] : [H, W, 1] + mask = self._downscale_if_required(batch["mask"]) + mask = mask.to(self.device) + assert mask.shape[:2] == gt_img.shape[:2] == pred_img.shape[:2] + gt_img = gt_img * mask + pred_img = pred_img * mask + + Ll1_img = torch.abs(gt_img - pred_img) + if ( + self.step >= self.config.start_robust_mask_at + and self.config.enable_robust_mask + ): + robust_mask = self.robust_mask(Ll1_img) + gt_img = gt_img * robust_mask + pred_img = pred_img * robust_mask + Ll1 = (Ll1_img * robust_mask).mean() + else: + Ll1 = Ll1_img.mean() + + simloss = 1 - self.ssim( + gt_img.permute(2, 0, 1)[None, ...], pred_img.permute(2, 0, 1)[None, ...] + ) + if self.config.use_scale_regularization and self.step % 10 == 0: + scale_exp = torch.exp(self.scales) + scale_reg = ( + torch.maximum( + scale_exp.amax(dim=-1) / scale_exp.amin(dim=-1), + torch.tensor(self.config.max_gauss_ratio), + ) + - self.config.max_gauss_ratio + ) + scale_reg = 0.1 * scale_reg.mean() + else: + scale_reg = torch.tensor(0.0).to(self.device) + + if self.config.enable_alpha_loss: + alpha_loss = torch.tensor(0.0).to(self.device) + background = outputs["background"] + alpha = outputs["accumulation"] + # for those pixel are well represented by bg and has low alpha, we encourage the gaussian to be transparent + bg_mask = torch.abs(gt_img - background).mean(dim=-1, keepdim=True) < 0.003 + # use a box filter to avoid penalty high frequency parts + f = 3 + window = (torch.ones((f, f)).view(1, 1, f, f) / (f * f)).cuda() + bg_mask = ( + torch.nn.functional.conv2d( + bg_mask.float().unsqueeze(0).permute(0, 3, 1, 2), + window, + stride=1, + padding="same", + ) + .permute(0, 2, 3, 1) + .squeeze(0) + ) + alpha_mask = bg_mask > 0.6 + # prevent NaN + if alpha_mask.sum() != 0: + alpha_loss = alpha[alpha_mask].mean() * 0.15 + else: + alpha_loss = torch.tensor(0.0).to(self.device) + + loss_dict = { + "main_loss": (1 - self.config.ssim_lambda) * Ll1 + + self.config.ssim_lambda * simloss, + "scale_reg": scale_reg, + "alpha_loss": alpha_loss, + } + + if self.training: + # Add loss from camera optimizer + self.camera_optimizer.get_loss_dict(loss_dict) + + return loss_dict + + @torch.no_grad() + def get_outputs_for_camera( + self, camera: Cameras, obb_box: Optional[OrientedBox] = None + ) -> Dict[str, torch.Tensor]: + """Takes in a camera, generates the raybundle, and computes the output of the model. + Overridden for a camera-based gaussian model. + + Args: + camera: generates raybundle + """ + assert camera is not None, "must provide camera to gaussian model" + self.set_crop(obb_box) + outs = self.get_outputs(camera.to(self.device)) + return outs # type: ignore + + def get_image_metrics_and_images( + self, outputs: Dict[str, torch.Tensor], batch: Dict[str, torch.Tensor] + ) -> Tuple[Dict[str, float], Dict[str, torch.Tensor]]: + """Writes the test image outputs. + + Args: + image_idx: Index of the image. + step: Current step. + batch: Batch of data. + outputs: Outputs of the model. + + Returns: + A dictionary of metrics. + """ + + gt_rgb = self.composite_with_background( + self.get_gt_img(batch["image"]), outputs["background"] + ) + predicted_rgb = outputs["rgb"] + combined_rgb = torch.cat([gt_rgb, predicted_rgb], dim=1) + + # hacked version, only eval on the right half of the image + # cut the image in half,HW3 + if self.config.eval_right_half: + gt_rgb = gt_rgb[:, gt_rgb.shape[1] // 2 :, :] + predicted_rgb = predicted_rgb[:, predicted_rgb.shape[1] // 2 :, :] + + # cv2.imwrite("gt.png", (gt_rgb.detach().cpu().numpy() * 255).astype(np.uint8)) + # cv2.imwrite("p.png", (predicted_rgb.detach().cpu().numpy() * 255).astype(np.uint8)) + # cv2.imwrite("c.png", (combined_rgb.detach().cpu().numpy() * 255).astype(np.uint8)) + # exit() + + # Switch images from [H, W, C] to [1, C, H, W] for metrics computations + gt_rgb = torch.moveaxis(gt_rgb, -1, 0)[None, ...] + predicted_rgb = torch.moveaxis(predicted_rgb, -1, 0)[None, ...] + + psnr = self.psnr(gt_rgb, predicted_rgb) + ssim = self.ssim(gt_rgb, predicted_rgb) + lpips = self.lpips(gt_rgb, predicted_rgb) + + # all of these metrics will be logged as scalars + metrics_dict = {"psnr": float(psnr.item()), "ssim": float(ssim)} # type: ignore + metrics_dict["lpips"] = float(lpips) + + images_dict = {"img": combined_rgb} + + return metrics_dict, images_dict + + @torch.no_grad() + def robust_mask(self, errors: torch.Tensor): + """Computes Robust Mask. + + Args: + errors: f32[h,w,c]. Per-subpixel errors. + inlier_threshold: f32[]. Upper bound on per-pixel loss to use to determine + if a pixel is an inlier or not. + config: Config object. + + Returns: + mask: f32[h,w,1]. + """ + epsilon = 1e-3 + # never mask the upper of the image + errors[: int(errors.shape[0] * self.config.never_mask_upper), :, :] = 0.0 + Ll1 = errors.mean() + # update max and min of Loss + if ( + Ll1 > self.max_loss + or self.step % self.config.robust_mask_reset_interval == 0 + ): + self.max_loss = Ll1 + if Ll1 < self.min_loss: + self.min_loss = Ll1 + + mask_range_min, mask_range_max = self.config.robust_mask_percentage + mask_percentage = (Ll1 - self.min_loss) / ( + (self.max_loss - self.min_loss) + 1e-6 + ) * (mask_range_max - mask_range_min) + mask_range_min + + errors = errors.view(1, errors.shape[0], errors.shape[1], errors.shape[2]) + error_per_pixel = torch.mean(errors, dim=-1, keepdim=True) + inlier_threshold = torch.quantile(error_per_pixel, 1 - mask_percentage) + mask = torch.ones_like(error_per_pixel) + # 1.0 for inlier pixels. + is_inlier_loss = (error_per_pixel <= inlier_threshold).float() + # stats["is_inlier_loss"] = torch.mean(is_inlier_loss) + + # Apply 5x5 box filter. + f = 5 + window = (torch.ones((f, f)).view(1, 1, f, f) / (f * f)).cuda() + has_inlier_neighbors = torch.nn.functional.conv2d( + is_inlier_loss.permute(0, 3, 1, 2), window, stride=1, padding="same" + ) + has_inlier_neighbors = has_inlier_neighbors.permute(0, 2, 3, 1) # [n,h,w,1] + + # Binarize after smoothing. + has_inlier_neighbors = (has_inlier_neighbors > 0.4).float() + + # A pixel is an inlier if it is an inlier according to any of the above + # criteria. + mask = ( + (has_inlier_neighbors + is_inlier_loss > epsilon) + .float() + .view(errors.shape[1], errors.shape[2], 1) + ) + + del errors + del has_inlier_neighbors + del is_inlier_loss + del error_per_pixel + return mask + + @torch.no_grad() + def render_equirect(self, W, appearance_embed=None): + H = W // 2 + # For equirect, fx = fy = height = width/2 + fx, fy = torch.tensor(H), torch.tensor(H) + cx, cy = torch.tensor(W / 2), torch.tensor(H / 2) + # R = torch.eye(3, device=self.device) + from nerfstudio.cameras.cameras import CameraType + + # flip the z and y axes to align with gsplat conventions + # R = torch.diag(torch.tensor([1, -1, -1], device=self.device, dtype=R.dtype)) + # combine R into c2w + # c2w = torch.eye(4, device=self.device) + # c2w[:3, :3] = R + c2w = torch.tensor( + [[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]], + device=self.device, + ) + c2w = c2w[None, :3, :] + camera = Cameras( + fx=fx, + fy=fy, + cx=cx, + cy=cy, + camera_to_worlds=c2w, + camera_type=CameraType.EQUIRECTANGULAR, + ).to(self.device) + ray_bundle = camera.generate_rays(0, keep_shape=False, disable_distortion=True) + assert self.bg_model is not None + background = ( + self.bg_model(ray_bundle, appearance_embed) + .float() + .clamp(0, 1) + .reshape(H, W, 3) + ) + print("background shape: ", background.shape) + print("background: ", background) + # exit() + self.save_image(background, "output_images/equirect_bg.jpg") + return background + + # def save_image(self, img, path): + # import os + + # import PIL + + # img = img.detach().cpu().numpy() + # img = (img * 255).astype(np.uint8) + # img = PIL.Image.fromarray(img) + # # create output_images folder if it doesn't exist + # if not os.path.exists(path=os.path.dirname(path)): + # os.makedirs(os.path.dirname(path)) + # img.save(path) diff --git a/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model_patch_minimal.diff b/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model_patch_minimal.diff new file mode 100644 index 0000000000..2a3d2b5f91 --- /dev/null +++ b/Extra-Methods-Patches/splatfacto-w/splatfactow/splatfactow_model_patch_minimal.diff @@ -0,0 +1,63 @@ +@@ -553,6 +553,30 @@ + + for group, param in param_groups.items(): + self.dup_in_optim(optimizers.optimizers[group], dup_mask, param, n) + ++ def _collapse_radii_to_pointwise(self, radii: torch.Tensor) -> torch.Tensor: ++ """Return one scalar radius per gaussian across gsplat versions. ++ ++ Older gsplat versions returned radii shaped like ``[N]`` or ``[N, 1]``. ++ Newer versions may return ``[N, 2]`` (per-axis image-space radii). For ++ densification and visibility bookkeeping we only need a single scalar per ++ gaussian, so we conservatively take the maximum positive radius across the ++ trailing dimensions. ++ """ ++ radii = radii.to(dtype=torch.float32) ++ if radii.ndim <= 1: ++ return radii.reshape(-1) ++ return radii.reshape(radii.shape[0], -1).amax(dim=-1) ++ ++ def _get_visible_mask_and_radii(self) -> Tuple[torch.Tensor, torch.Tensor]: ++ """Build a per-gaussian visibility mask and scalar radii. ++ ++ This is backward compatible with gsplat variants that expose radii as ++ ``[N]``, ``[N, 1]`` or ``[N, 2]``. ++ """ ++ radii_1d = self._collapse_radii_to_pointwise(self.radii) ++ visible_mask = radii_1d > 0 ++ return visible_mask.reshape(-1), radii_1d.reshape(-1) ++ + def after_train(self, step: int): + assert step == self.step + # to save some training time, we no longer need to update those stats post refinement +@@ -560,8 +584,15 @@ + + return + with torch.no_grad(): + # keep track of a moving average of grad norms +- visible_mask = (self.radii > 0).flatten() +- grads = self.xys.absgrad[0][visible_mask].norm(dim=-1) # type: ignore ++ visible_mask, radii_1d = self._get_visible_mask_and_radii() ++ grads_xy = self.xys.absgrad[0] # type: ignore[index] ++ if visible_mask.shape[0] != grads_xy.shape[0]: ++ raise RuntimeError( ++ "Incompatible gsplat metadata shapes: " ++ f"visible mask has shape {tuple(visible_mask.shape)} while " ++ f"means2d gradients have shape {tuple(grads_xy.shape)}." ++ ) ++ grads = grads_xy[visible_mask].norm(dim=-1) + # print(f"grad norm min {grads.min().item()} max {grads.max().item()} mean {grads.mean().item()} size {grads.shape}") + if self.xys_grad_norm is None: + self.xys_grad_norm = torch.zeros( +@@ -575,8 +606,8 @@ + + self.xys_grad_norm[visible_mask] += grads + # update the max screen size, as a ratio of number of pixels + if self.max_2Dsize is None: +- self.max_2Dsize = torch.zeros_like(self.radii, dtype=torch.float32) +- newradii = self.radii.detach()[visible_mask] ++ self.max_2Dsize = torch.zeros_like(radii_1d, dtype=torch.float32) ++ newradii = radii_1d.detach()[visible_mask] + self.max_2Dsize[visible_mask] = torch.maximum( + self.max_2Dsize[visible_mask], + newradii / float(max(self.last_size[0], self.last_size[1])), diff --git a/Extra-Methods-Patches/tetra-nerf/CMakeLists.txt b/Extra-Methods-Patches/tetra-nerf/CMakeLists.txt new file mode 100644 index 0000000000..2ed590dda6 --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/CMakeLists.txt @@ -0,0 +1,152 @@ +cmake_minimum_required(VERSION 3.22.1) +project(fast_traversal LANGUAGES CXX CUDA) + +if(WIN32) + add_compile_options("$<$:/bigobj>") + string(REPLACE "-fPIC" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") + string(REPLACE "-fPIC" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + string(REPLACE "-fPIC" "" CMAKE_CUDA_FLAGS "${CMAKE_CUDA_FLAGS}") +endif() + +enable_language(CUDA) + +include(FetchContent) + +set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) +set(CMAKE_BUILD_TYPE "Release") + +find_library(libcnpy cnpy ${CONDA_PREFIX}/lib) +include_directories(${CONDA_PREFIX}/include) + +find_package(Torch REQUIRED) +find_package(CGAL REQUIRED) + +FetchContent_Declare( + pybind11 + GIT_REPOSITORY https://github.com/pybind/pybind11.git + GIT_TAG v2.9.2 +) +FetchContent_MakeAvailable(pybind11) + +if(WIN32 AND TARGET pybind11::windows_extras) + set_property(TARGET pybind11::windows_extras PROPERTY INTERFACE_COMPILE_OPTIONS "") +endif() + +if(WIN32) + add_compile_options("$<$:/bigobj>") +endif() + +if(NOT WIN32) + add_link_options(-flto=auto) +endif() + +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") +set(BUILD_DIRECTORY "${CMAKE_BINARY_DIR}/build") +set(CUDA_GENERATED_OUTPUT_DIR "${BUILD_DIRECTORY}") + +# -------------------------------------------------------------------------- +# Canonical incoming cache/env values from setup.py / bootstrap +# -------------------------------------------------------------------------- +if(NOT OPTIX_ROOT_DIR AND DEFINED ENV{OPTIX_ROOT_DIR}) + set(OPTIX_ROOT_DIR "$ENV{OPTIX_ROOT_DIR}" CACHE PATH "OptiX root directory" FORCE) +endif() + +if(NOT OPTIX_INSTALL_DIR AND DEFINED ENV{OPTIX_INSTALL_DIR}) + set(OPTIX_INSTALL_DIR "$ENV{OPTIX_INSTALL_DIR}" CACHE PATH "OptiX install directory" FORCE) +endif() + +if(NOT OPTIX_INCLUDE_DIR AND DEFINED ENV{OPTIX_INCLUDE_DIR}) + set(OPTIX_INCLUDE_DIR "$ENV{OPTIX_INCLUDE_DIR}" CACHE PATH "OptiX include directory" FORCE) +endif() + +if(NOT OPTIX_ROOT_DIR AND NOT OPTIX_INSTALL_DIR AND DEFINED ENV{OPTIX_PATH}) + set(OPTIX_INSTALL_DIR "$ENV{OPTIX_PATH}" CACHE PATH "OptiX install directory" FORCE) +endif() + +find_package(OptiX REQUIRED) +find_package(CUDA REQUIRED) + +set(CUDA_SEPARABLE_COMPILATION ON) + +include_directories( + "${OptiX_INCLUDE}" + "${CMAKE_CURRENT_SOURCE_DIR}/cuda" + ${CUDA_INCLUDE_DIRS} +) + +find_program(BIN2C bin2c DOC "Path to the cuda-sdk bin2c executable.") + +macro(cuda_compile_and_embed output_var generated_files_name) + set(c_var_name ${output_var}) + set(generated_files "${${generated_files_name}}") + list(GET ${generated_files_name} 0 ptx_file) + get_filename_component(embedded_file ${ptx_file}_embedded.cpp NAME) + set(embedded_file "${BUILD_DIRECTORY}/${embedded_file}") + add_custom_command( + OUTPUT ${embedded_file} + COMMAND ${BIN2C} --padd 0 --type char --name ${c_var_name} ${ptx_file} > ${embedded_file} + DEPENDS ${generated_files} + COMMENT "compiling (and embedding ptx)") + set(${output_var} ${embedded_file}) + list(APPEND ${generated_files_name} ${embedded_file}) +endmacro() + +CUDA_WRAP_SRCS(traversal PTX generated_files_trace_rays + src/optix_types.h + src/optix/optix_trace_rays.cu + src/utils/preprocessor.h + src/utils/vec_math.h + OPTIONS -rdc true +) +cuda_compile_and_embed(ptx_code_file generated_files_trace_rays) + +CUDA_WRAP_SRCS(traversal PTX generated_files_find_tetrahedra + src/optix_types.h + src/optix/optix_find_tetrahedra.cu + src/utils/preprocessor.h + src/utils/vec_math.h + OPTIONS -rdc true +) +cuda_compile_and_embed(ptx_code_file_find_tetrahedra generated_files_find_tetrahedra) + +CUDA_WRAP_SRCS(traversal PTX generated_files_trace_rays_triangles + src/optix_types.h + src/optix/optix_trace_rays_triangles.cu + src/utils/preprocessor.h + src/utils/vec_math.h + OPTIONS -rdc true +) +cuda_compile_and_embed(ptx_code_file_triangles generated_files_trace_rays_triangles) + +set(generated_files + ${generated_files_trace_rays} + ${generated_files_find_tetrahedra} + ${generated_files_trace_rays_triangles} +) + +if(NOT WIN32) + add_link_options(-flto=auto) +endif() + +pybind11_add_module( + tetranerf_cpp_extension + src/tetrahedra_tracer.cu + src/tetrahedra_tracer.cpp + src/triangulation.cpp + src/py_binding.cpp + ${generated_files} +) + +target_link_libraries(tetranerf_cpp_extension PRIVATE ${CUDA_LIBRARIES} ${TORCH_LIBRARIES}) +target_link_libraries(tetranerf_cpp_extension PRIVATE CGAL::CGAL) +target_compile_features(tetranerf_cpp_extension PRIVATE cxx_std_17) + +set_target_properties( + tetranerf_cpp_extension + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/tetranerf/utils/extension" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" +) \ No newline at end of file diff --git a/Extra-Methods-Patches/tetra-nerf/cmake/FindCUDA.cmake b/Extra-Methods-Patches/tetra-nerf/cmake/FindCUDA.cmake new file mode 100644 index 0000000000..10cb2c8e4f --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/cmake/FindCUDA.cmake @@ -0,0 +1,2272 @@ +#.rst: +# FindCUDA +# -------- +# +# Tools for building CUDA C files: libraries and build dependencies. +# +# This script locates the NVIDIA CUDA C tools. It should work on linux, +# windows, and mac and should be reasonably up to date with CUDA C +# releases. +# +# This script makes use of the standard find_package arguments of +# , REQUIRED and QUIET. CUDA_FOUND will report if an +# acceptable version of CUDA was found. +# +# The script will prompt the user to specify CUDA_TOOLKIT_ROOT_DIR if +# the prefix cannot be determined by the location of nvcc in the system +# path and REQUIRED is specified to find_package(). To use a different +# installed version of the toolkit set the environment variable +# CUDA_BIN_PATH before running cmake (e.g. +# CUDA_BIN_PATH=/usr/local/cuda1.0 instead of the default +# /usr/local/cuda) or set CUDA_TOOLKIT_ROOT_DIR after configuring. If +# you change the value of CUDA_TOOLKIT_ROOT_DIR, various components that +# depend on the path will be relocated. +# +# It might be necessary to set CUDA_TOOLKIT_ROOT_DIR manually on certain +# platforms, or to use a cuda runtime not installed in the default +# location. In newer versions of the toolkit the cuda library is +# included with the graphics driver- be sure that the driver version +# matches what is needed by the cuda runtime version. +# +# The following variables affect the behavior of the macros in the +# script (in alphebetical order). Note that any of these flags can be +# changed multiple times in the same directory before calling +# CUDA_ADD_EXECUTABLE, CUDA_ADD_LIBRARY, CUDA_COMPILE, CUDA_COMPILE_PTX, +# CUDA_COMPILE_FATBIN, CUDA_COMPILE_CUBIN or CUDA_WRAP_SRCS:: +# +# CUDA_64_BIT_DEVICE_CODE (Default matches host bit size) +# -- Set to ON to compile for 64 bit device code, OFF for 32 bit device code. +# Note that making this different from the host code when generating object +# or C files from CUDA code just won't work, because size_t gets defined by +# nvcc in the generated source. If you compile to PTX and then load the +# file yourself, you can mix bit sizes between device and host. +# +# CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE (Default ON) +# -- Set to ON if you want the custom build rule to be attached to the source +# file in Visual Studio. Turn OFF if you add the same cuda file to multiple +# targets. +# +# This allows the user to build the target from the CUDA file; however, bad +# things can happen if the CUDA source file is added to multiple targets. +# When performing parallel builds it is possible for the custom build +# command to be run more than once and in parallel causing cryptic build +# errors. VS runs the rules for every source file in the target, and a +# source can have only one rule no matter how many projects it is added to. +# When the rule is run from multiple targets race conditions can occur on +# the generated file. Eventually everything will get built, but if the user +# is unaware of this behavior, there may be confusion. It would be nice if +# this script could detect the reuse of source files across multiple targets +# and turn the option off for the user, but no good solution could be found. +# +# CUDA_BUILD_CUBIN (Default OFF) +# -- Set to ON to enable and extra compilation pass with the -cubin option in +# Device mode. The output is parsed and register, shared memory usage is +# printed during build. +# +# CUDA_BUILD_EMULATION (Default OFF for device mode) +# -- Set to ON for Emulation mode. -D_DEVICEEMU is defined for CUDA C files +# when CUDA_BUILD_EMULATION is TRUE. +# +# CUDA_ENABLE_BATCHING (Default OFF) +# -- Set to ON to enable batch compilation of CUDA source files. This only has +# effect on Visual Studio targets +# +# CUDA_GENERATED_OUTPUT_DIR (Default CMAKE_CURRENT_BINARY_DIR) +# -- Set to the path you wish to have the generated files placed. If it is +# blank output files will be placed in CMAKE_CURRENT_BINARY_DIR. +# Intermediate files will always be placed in +# CMAKE_CURRENT_BINARY_DIR/CMakeFiles. +# +# CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE (Default ON for VS, +# OFF otherwise) +# -- Instead of waiting until build time compute dependencies, do it during +# configure time. Note that dependencies are still generated during +# build, so that if they change the build system can be updated. This +# mainly removes the need for configuring once after the first build to +# load the dependies into the build system. +# +# CUDA_CHECK_DEPENDENCIES_DURING_COMPILE (Default ON for VS, +# OFF otherwise) +# -- During build, the file level dependencies are checked. If all +# dependencies are older than the generated file, the generated file isn't +# compiled but touched (time stamp updated) so the driving build system +# thinks it has been compiled. +# +# CUDA_HOST_COMPILATION_CPP (Default ON) +# -- Set to OFF for C compilation of host code. +# +# CUDA_HOST_COMPILER (Default CMAKE_C_COMPILER, $(VCInstallDir)/bin for VS) +# -- Set the host compiler to be used by nvcc. Ignored if -ccbin or +# --compiler-bindir is already present in the CUDA_NVCC_FLAGS or +# CUDA_NVCC_FLAGS_ variables. For Visual Studio targets +# $(VCInstallDir)/bin is a special value that expands out to the path when +# the command is run from within VS. +# +# CUDA_NVCC_FLAGS +# CUDA_NVCC_FLAGS_ +# -- Additional NVCC command line arguments. NOTE: multiple arguments must be +# semi-colon delimited (e.g. --compiler-options;-Wall) +# +# CUDA_PROPAGATE_HOST_FLAGS (Default ON) +# -- Set to ON to propagate CMAKE_{C,CXX}_FLAGS and their configuration +# dependent counterparts (e.g. CMAKE_C_FLAGS_DEBUG) automatically to the +# host compiler through nvcc's -Xcompiler flag. This helps make the +# generated host code match the rest of the system better. Sometimes +# certain flags give nvcc problems, and this will help you turn the flag +# propagation off. This does not affect the flags supplied directly to nvcc +# via CUDA_NVCC_FLAGS or through the OPTION flags specified through +# CUDA_ADD_LIBRARY, CUDA_ADD_EXECUTABLE, or CUDA_WRAP_SRCS. Flags used for +# shared library compilation are not affected by this flag. +# +# CUDA_SEPARABLE_COMPILATION (Default OFF) +# -- If set this will enable separable compilation for all CUDA runtime object +# files. If used outside of CUDA_ADD_EXECUTABLE and CUDA_ADD_LIBRARY +# (e.g. calling CUDA_WRAP_SRCS directly), +# CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME and +# CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS should be called. +# +# CUDA_SOURCE_PROPERTY_FORMAT +# -- If this source file property is set, it can override the format specified +# to CUDA_WRAP_SRCS (OBJ, PTX, CUBIN, or FATBIN). If an input source file +# is not a .cu file, setting this file will cause it to be treated as a .cu +# file. See documentation for set_source_files_properties on how to set +# this property. +# +# CUDA_USE_STATIC_CUDA_RUNTIME (Default ON) +# -- When enabled the static version of the CUDA runtime library will be used +# in CUDA_LIBRARIES. If the version of CUDA configured doesn't support +# this option, then it will be silently disabled. +# +# CUDA_VERBOSE_BUILD (Default OFF) +# -- Set to ON to see all the commands used when building the CUDA file. When +# using a Makefile generator the value defaults to VERBOSE (run make +# VERBOSE=1 to see output), although setting CUDA_VERBOSE_BUILD to ON will +# always print the output. +# +# The script creates the following macros (in alphebetical order):: +# +# CUDA_ADD_CUFFT_TO_TARGET( cuda_target ) +# -- Adds the cufft library to the target (can be any target). Handles whether +# you are in emulation mode or not. +# +# CUDA_ADD_CUBLAS_TO_TARGET( cuda_target ) +# -- Adds the cublas library to the target (can be any target). Handles +# whether you are in emulation mode or not. +# +# CUDA_ADD_EXECUTABLE( cuda_target file0 file1 ... +# [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [OPTIONS ...] ) +# -- Creates an executable "cuda_target" which is made up of the files +# specified. All of the non CUDA C files are compiled using the standard +# build rules specified by CMAKE and the cuda files are compiled to object +# files using nvcc and the host compiler. In addition CUDA_INCLUDE_DIRS is +# added automatically to include_directories(). Some standard CMake target +# calls can be used on the target after calling this macro +# (e.g. set_target_properties and target_link_libraries), but setting +# properties that adjust compilation flags will not affect code compiled by +# nvcc. Such flags should be modified before calling CUDA_ADD_EXECUTABLE, +# CUDA_ADD_LIBRARY or CUDA_WRAP_SRCS. +# +# CUDA_ADD_LIBRARY( cuda_target file0 file1 ... +# [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [OPTIONS ...] ) +# -- Same as CUDA_ADD_EXECUTABLE except that a library is created. +# +# CUDA_BUILD_CLEAN_TARGET() +# -- Creates a convience target that deletes all the dependency files +# generated. You should make clean after running this target to ensure the +# dependency files get regenerated. +# +# CUDA_COMPILE( generated_files file0 file1 ... [STATIC | SHARED | MODULE] +# [OPTIONS ...] ) +# -- Returns a list of generated files from the input source files to be used +# with ADD_LIBRARY or ADD_EXECUTABLE. +# +# CUDA_COMPILE_PTX( generated_files file0 file1 ... [OPTIONS ...] ) +# -- Returns a list of PTX files generated from the input source files. +# +# CUDA_COMPILE_FATBIN( generated_files file0 file1 ... [OPTIONS ...] ) +# -- Returns a list of FATBIN files generated from the input source files. +# +# CUDA_COMPILE_CUBIN( generated_files file0 file1 ... [OPTIONS ...] ) +# -- Returns a list of CUBIN files generated from the input source files. +# +# CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME( output_file_var +# cuda_target +# object_files ) +# -- Compute the name of the intermediate link file used for separable +# compilation. This file name is typically passed into +# CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS. output_file_var is produced +# based on cuda_target the list of objects files that need separable +# compilation as specified by object_files. If the object_files list is +# empty, then output_file_var will be empty. This function is called +# automatically for CUDA_ADD_LIBRARY and CUDA_ADD_EXECUTABLE. Note that +# this is a function and not a macro. +# +# CUDA_INCLUDE_DIRECTORIES( path0 path1 ... ) +# -- Sets the directories that should be passed to nvcc +# (e.g. nvcc -Ipath0 -Ipath1 ... ). These paths usually contain other .cu +# files. +# +# +# CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS( output_file_var cuda_target +# nvcc_flags object_files) +# -- Generates the link object required by separable compilation from the given +# object files. This is called automatically for CUDA_ADD_EXECUTABLE and +# CUDA_ADD_LIBRARY, but can be called manually when using CUDA_WRAP_SRCS +# directly. When called from CUDA_ADD_LIBRARY or CUDA_ADD_EXECUTABLE the +# nvcc_flags passed in are the same as the flags passed in via the OPTIONS +# argument. The only nvcc flag added automatically is the bitness flag as +# specified by CUDA_64_BIT_DEVICE_CODE. Note that this is a function +# instead of a macro. +# +# CUDA_SELECT_NVCC_ARCH_FLAGS(out_variable [target_CUDA_architectures]) +# -- Selects GPU arch flags for nvcc based on target_CUDA_architectures +# target_CUDA_architectures : Auto | Common | All | LIST(ARCH_AND_PTX ...) +# - "Auto" detects local machine GPU compute arch at runtime. +# - "Common" and "All" cover common and entire subsets of architectures +# ARCH_AND_PTX : NAME | NUM.NUM | NUM.NUM(NUM.NUM) | NUM.NUM+PTX +# NAME: Fermi Kepler Maxwell Kepler+Tegra Kepler+Tesla Maxwell+Tegra Pascal +# NUM: Any number. Only those pairs are currently accepted by NVCC though: +# 2.0 2.1 3.0 3.2 3.5 3.7 5.0 5.2 5.3 6.0 6.2 +# Returns LIST of flags to be added to CUDA_NVCC_FLAGS in ${out_variable} +# Additionally, sets ${out_variable}_readable to the resulting numeric list +# Example: +# CUDA_SELECT_NVCC_ARCH_FLAGS(ARCH_FLAGS 3.0 3.5+PTX 5.2(5.0) Maxwell) +# LIST(APPEND CUDA_NVCC_FLAGS ${ARCH_FLAGS}) +# +# More info on CUDA architectures: https://en.wikipedia.org/wiki/CUDA +# Note that this is a function instead of a macro. +# +# CUDA_WRAP_SRCS ( cuda_target format generated_files file0 file1 ... +# [STATIC | SHARED | MODULE] [OPTIONS ...] ) +# -- This is where all the magic happens. CUDA_ADD_EXECUTABLE, +# CUDA_ADD_LIBRARY, CUDA_COMPILE, and CUDA_COMPILE_PTX all call this +# function under the hood. +# +# Given the list of files (file0 file1 ... fileN) this macro generates +# custom commands that generate either PTX or linkable objects (use "PTX" or +# "OBJ" for the format argument to switch). Files that don't end with .cu +# or have the HEADER_FILE_ONLY property are ignored. +# +# The arguments passed in after OPTIONS are extra command line options to +# give to nvcc. You can also specify per configuration options by +# specifying the name of the configuration followed by the options. General +# options must precede configuration specific options. Not all +# configurations need to be specified, only the ones provided will be used. +# +# OPTIONS -DFLAG=2 "-DFLAG_OTHER=space in flag" +# DEBUG -g +# RELEASE --use_fast_math +# RELWITHDEBINFO --use_fast_math;-g +# MINSIZEREL --use_fast_math +# +# For certain configurations (namely VS generating object files with +# CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE set to ON), no generated file will +# be produced for the given cuda file. This is because when you add the +# cuda file to Visual Studio it knows that this file produces an object file +# and will link in the resulting object file automatically. +# +# This script will also generate a separate cmake script that is used at +# build time to invoke nvcc. This is for several reasons. +# +# 1. nvcc can return negative numbers as return values which confuses +# Visual Studio into thinking that the command succeeded. The script now +# checks the error codes and produces errors when there was a problem. +# +# 2. nvcc has been known to not delete incomplete results when it +# encounters problems. This confuses build systems into thinking the +# target was generated when in fact an unusable file exists. The script +# now deletes the output files if there was an error. +# +# 3. By putting all the options that affect the build into a file and then +# make the build rule dependent on the file, the output files will be +# regenerated when the options change. +# +# This script also looks at optional arguments STATIC, SHARED, or MODULE to +# determine when to target the object compilation for a shared library. +# BUILD_SHARED_LIBS is ignored in CUDA_WRAP_SRCS, but it is respected in +# CUDA_ADD_LIBRARY. On some systems special flags are added for building +# objects intended for shared libraries. A preprocessor macro, +# _EXPORTS is defined when a shared library compilation is +# detected. +# +# Flags passed into add_definitions with -D or /D are passed along to nvcc. +# +# +# +# The script defines the following variables:: +# +# CUDA_VERSION_MAJOR -- The major version of cuda as reported by nvcc. +# CUDA_VERSION_MINOR -- The minor version. +# CUDA_VERSION +# CUDA_VERSION_STRING -- CUDA_VERSION_MAJOR.CUDA_VERSION_MINOR +# CUDA_HAS_FP16 -- Whether a short float (float16,fp16) is supported. +# +# CUDA_TOOLKIT_ROOT_DIR -- Path to the CUDA Toolkit (defined if not set). +# CUDA_SDK_ROOT_DIR -- Path to the CUDA SDK. Use this to find files in the +# SDK. This script will not directly support finding +# specific libraries or headers, as that isn't +# supported by NVIDIA. If you want to change +# libraries when the path changes see the +# FindCUDA.cmake script for an example of how to clear +# these variables. There are also examples of how to +# use the CUDA_SDK_ROOT_DIR to locate headers or +# libraries, if you so choose (at your own risk). +# CUDA_INCLUDE_DIRS -- Include directory for cuda headers. Added automatically +# for CUDA_ADD_EXECUTABLE and CUDA_ADD_LIBRARY. +# CUDA_LIBRARIES -- Cuda RT library. +# CUDA_CUDA_LIBRARY -- Cuda driver API library. +# CUDA_CUFFT_LIBRARIES -- Device or emulation library for the Cuda FFT +# implementation (alternative to: +# CUDA_ADD_CUFFT_TO_TARGET macro) +# CUDA_CUBLAS_LIBRARIES -- Device or emulation library for the Cuda BLAS +# implementation (alternative to: +# CUDA_ADD_CUBLAS_TO_TARGET macro). +# CUDA_cudart_static_LIBRARY -- Statically linkable cuda runtime library. +# Only available for CUDA version 5.5+ +# CUDA_cudadevrt_LIBRARY -- Device runtime library. +# Required for separable compilation. +# CUDA_cupti_LIBRARY -- CUDA Profiling Tools Interface library. +# Only available for CUDA version 4.0+. +# CUDA_curand_LIBRARY -- CUDA Random Number Generation library. +# Only available for CUDA version 3.2+. +# CUDA_cusolver_LIBRARY -- CUDA Direct Solver library. +# Only available for CUDA version 7.0+. +# CUDA_cusparse_LIBRARY -- CUDA Sparse Matrix library. +# Only available for CUDA version 3.2+. +# CUDA_npp_LIBRARY -- NVIDIA Performance Primitives lib. +# Only available for CUDA version 4.0+. +# CUDA_nppc_LIBRARY -- NVIDIA Performance Primitives lib (core). +# Only available for CUDA version 5.5+. +# CUDA_nppi_LIBRARY -- NVIDIA Performance Primitives lib (image processing). +# Only available for CUDA version 5.5+. +# CUDA_npps_LIBRARY -- NVIDIA Performance Primitives lib (signal processing). +# Only available for CUDA version 5.5+. +# CUDA_nvcuvenc_LIBRARY -- CUDA Video Encoder library. +# Only available for CUDA version 3.2+. +# Windows only. +# CUDA_nvcuvid_LIBRARY -- CUDA Video Decoder library. +# Only available for CUDA version 3.2+. +# Windows only. +# + +# James Bigler, NVIDIA Corp (nvidia.com - jbigler) +# Abe Stephens, SCI Institute -- http://www.sci.utah.edu/~abe/FindCuda.html +# +# Copyright (c) 2008 - 2021 NVIDIA Corporation. All rights reserved. +# +# Copyright (c) 2007-2009 +# Scientific Computing and Imaging Institute, University of Utah +# +# This code is licensed under the MIT License. See the FindCUDA.cmake script +# for the text of the license. + +# The MIT License +# +# License for the specific language governing rights and limitations under +# 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 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. +# +############################################################################### + +# FindCUDA.cmake + +# This macro helps us find the location of helper files we will need the full path to +macro(CUDA_FIND_HELPER_FILE _name _extension) + set(_full_name "${_name}.${_extension}") + # CMAKE_CURRENT_LIST_FILE contains the full path to the file currently being + # processed. Using this variable, we can pull out the current path, and + # provide a way to get access to the other files we need local to here. + get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) + set(CUDA_${_name} "${CMAKE_CURRENT_LIST_DIR}/FindCUDA/${_full_name}") + if(NOT EXISTS "${CUDA_${_name}}") + set(error_message "${_full_name} not found in ${CMAKE_CURRENT_LIST_DIR}/FindCUDA") + if(CUDA_FIND_REQUIRED) + message(FATAL_ERROR "${error_message}") + else() + if(NOT CUDA_FIND_QUIETLY) + message(STATUS "${error_message}") + endif() + endif() + endif() + # Set this variable as internal, so the user isn't bugged with it. + set(CUDA_${_name} ${CUDA_${_name}} CACHE INTERNAL "Location of ${_full_name}" FORCE) +endmacro() + +##################################################################### +## CUDA_INCLUDE_NVCC_DEPENDENCIES +## + +# So we want to try and include the dependency file if it exists. If +# it doesn't exist then we need to create an empty one, so we can +# include it. + +# If it does exist, then we need to check to see if all the files it +# depends on exist. If they don't then we should clear the dependency +# file and regenerate it later. This covers the case where a header +# file has disappeared or moved. + +macro(CUDA_INCLUDE_NVCC_DEPENDENCIES dependency_file) + set(CUDA_NVCC_DEPEND) + set(CUDA_NVCC_DEPEND_REGENERATE FALSE) + + + # Include the dependency file. Create it first if it doesn't exist . The + # INCLUDE puts a dependency that will force CMake to rerun and bring in the + # new info when it changes. DO NOT REMOVE THIS (as I did and spent a few + # hours figuring out why it didn't work. + if(NOT EXISTS ${dependency_file}) + file(WRITE ${dependency_file} "#FindCUDA.cmake generated file. Do not edit.\n") + endif() + # Always include this file to force CMake to run again next + # invocation and rebuild the dependencies. + #message("including dependency_file = ${dependency_file}") + include(${dependency_file}) + + # Now we need to verify the existence of all the included files + # here. If they aren't there we need to just blank this variable and + # make the file regenerate again. +# if(DEFINED CUDA_NVCC_DEPEND) +# message("CUDA_NVCC_DEPEND set") +# else() +# message("CUDA_NVCC_DEPEND NOT set") +# endif() + if(CUDA_NVCC_DEPEND) + #message("CUDA_NVCC_DEPEND found") + foreach(f ${CUDA_NVCC_DEPEND}) + # message("searching for ${f}") + if(NOT EXISTS ${f}) + #message("file ${f} not found") + set(CUDA_NVCC_DEPEND_REGENERATE TRUE) + endif() + endforeach() + else() + #message("CUDA_NVCC_DEPEND false") + # No dependencies, so regenerate the file. + set(CUDA_NVCC_DEPEND_REGENERATE TRUE) + endif() + + #message("CUDA_NVCC_DEPEND_REGENERATE = ${CUDA_NVCC_DEPEND_REGENERATE}") + # No incoming dependencies, so we need to generate them. Make the + # output depend on the dependency file itself, which should cause the + # rule to re-run. + if(CUDA_NVCC_DEPEND_REGENERATE) + set(CUDA_NVCC_DEPEND ${dependency_file}) + #message("Generating an empty dependency_file: ${dependency_file}") + file(WRITE ${dependency_file} "#FindCUDA.cmake generated file. Do not edit.\n") + endif() + +endmacro() + +############################################################################### +############################################################################### +# Setup variables' defaults +############################################################################### +############################################################################### + +# Allow the user to specify if the device code is supposed to be 32 or 64 bit. +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(CUDA_64_BIT_DEVICE_CODE_DEFAULT ON) +else() + set(CUDA_64_BIT_DEVICE_CODE_DEFAULT OFF) +endif() +option(CUDA_64_BIT_DEVICE_CODE "Compile device code in 64 bit mode" ${CUDA_64_BIT_DEVICE_CODE_DEFAULT}) + +# Attach the build rule to the source file in VS. This option +option(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE "Attach the build rule to the CUDA source file. Enable only when the CUDA source file is added to at most one target." ON) + +# Prints out extra information about the cuda file during compilation +option(CUDA_BUILD_CUBIN "Generate and parse .cubin files in Device mode." OFF) + +# Set whether we are using emulation or device mode. +option(CUDA_BUILD_EMULATION "Build in Emulation mode" OFF) + +# Enable batch builds +option(CUDA_ENABLE_BATCHING "Compile CUDA source files in parallel" OFF) +if(CUDA_ENABLE_BATCHING) + find_package(PythonInterp) + if(NOT PYTHONINTERP_FOUND) + message(SEND_ERROR "CUDA_ENABLE_BATCHING is enabled, but python wasn't found. Disabling") + set(CUDA_ENABLE_BATCHING OFF CACHE PATH "Compile CUDA source files in parallel" FORCE) + endif() +endif() + +# Where to put the generated output. +set(CUDA_GENERATED_OUTPUT_DIR "" CACHE PATH "Directory to put all the output files. If blank it will default to the CMAKE_CURRENT_BINARY_DIR") + +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set(_cuda_dependencies_default ON) +else() + set(_cuda_dependencies_default OFF) +endif() + +option(CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE "Generate dependencies during configure time instead of only during build time." ${_cuda_dependencies_default}) + +option(CUDA_CHECK_DEPENDENCIES_DURING_COMPILE "Checks the dependencies during compilation and suppresses generation if the dependencies have been met." ${_cuda_dependencies_default}) + +# Parse HOST_COMPILATION mode. +option(CUDA_HOST_COMPILATION_CPP "Generated file extension" ON) + +# Extra user settable flags +set(CUDA_NVCC_FLAGS "" CACHE STRING "Semi-colon delimit multiple arguments.") + +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)Tools/MSVC/$(VCToolsVersion)/bin/Host$(Platform)/$(PlatformTarget)") + if(MSVC_VERSION LESS 1910) + set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)bin") + endif() + + set(CUDA_HOST_COMPILER "${_CUDA_MSVC_HOST_COMPILER}" CACHE FILEPATH "Host side compiler used by NVCC") +else() + if(APPLE + AND "${CMAKE_C_COMPILER_ID}" MATCHES "Clang" + AND "${CMAKE_C_COMPILER}" MATCHES "/cc$") + # Using cc which is symlink to clang may let NVCC think it is GCC and issue + # unhandled -dumpspecs option to clang. Also in case neither + # CMAKE_C_COMPILER is defined (project does not use C language) nor + # CUDA_HOST_COMPILER is specified manually we should skip -ccbin and let + # nvcc use its own default C compiler. + # Only care about this on APPLE with clang to avoid + # following symlinks to things like ccache + if(DEFINED CMAKE_C_COMPILER AND NOT DEFINED CUDA_HOST_COMPILER) + get_filename_component(c_compiler_realpath "${CMAKE_C_COMPILER}" REALPATH) + # if the real path does not end up being clang then + # go back to using CMAKE_C_COMPILER + if(NOT "${c_compiler_realpath}" MATCHES "/clang$") + set(c_compiler_realpath "${CMAKE_C_COMPILER}") + endif() + else() + set(c_compiler_realpath "") + endif() + set(CUDA_HOST_COMPILER "${c_compiler_realpath}" CACHE FILEPATH "Host side compiler used by NVCC") + else() + set(CUDA_HOST_COMPILER "${CMAKE_C_COMPILER}" + CACHE FILEPATH "Host side compiler used by NVCC") + endif() +endif() + +# Set up CUDA_VC_VARS_ALL_BAT if it hasn't been specified. +# set CUDA_VC_VARS_ALL_BAT explicitly to avoid any attempts to locate it via this algorithm. +if(MSVC AND NOT CUDA_VC_VARS_ALL_BAT AND CUDA_ENABLE_BATCHING) + get_filename_component(_cuda_dependency_ccbin_dir "${CMAKE_CXX_COMPILER}" DIRECTORY) + #message(STATUS "_cuda_dependency_ccbin_dir = ${_cuda_dependency_ccbin_dir}") + # In VS 6-12 (1200-1800) the versions were 6 off. Starting in VS 14 (1900) it's only 5. + if(MSVC_VERSION VERSION_LESS 1900) + math(EXPR vs_major_version "${MSVC_VERSION} / 100 - 6") + find_file( CUDA_VC_VARS_ALL_BAT vcvarsall.bat PATHS "${_cuda_dependency_ccbin_dir}/../.." NO_DEFAULT_PATH ) + elseif(MSVC_VERSION VERSION_EQUAL 1900) + # Visual Studio 2015 + set(vs_major_version "15") + find_file( CUDA_VC_VARS_ALL_BAT vcvarsall.bat PATHS "${_cuda_dependency_ccbin_dir}/../.." NO_DEFAULT_PATH ) + elseif(MSVC_VERSION VERSION_LESS 1920) + # Visual Studio 2017 + set(vs_major_version "15") + find_file( CUDA_VC_VARS_ALL_BAT vcvarsall.bat PATHS "${_cuda_dependency_ccbin_dir}/../../../../../../Auxiliary/Build" NO_DEFAULT_PATH ) + else() + # Visual Studio 2019 + set(vs_major_version "16") + find_file( CUDA_VC_VARS_ALL_BAT vcvarsall.bat PATHS "${_cuda_dependency_ccbin_dir}/../../../../../../Auxiliary/Build" NO_DEFAULT_PATH ) + endif() + if( NOT CUDA_VC_VARS_ALL_BAT ) + # See if we can get VS install location from the registry. Registry searches can only + # be accomplished via a CACHE variable, unfortunately. + get_filename_component(_cuda_vs_dir_tmp "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\${vs_major_version}.0\\Setup\\VS;ProductDir]" REALPATH CACHE) + if( _cuda_vs_dir_tmp ) + set( CUDA_VS_DIR ${_cuda_vs_dir_tmp} ) + unset( _cuda_vs_dir_tmp CACHE ) + endif() + find_file( CUDA_VC_VARS_ALL_BAT vcvarsall.bat PATHS ${CUDA_VS_DIR}/VC/bin ${CUDA_VS_DIR}/VC/Auxiliary/Build NO_DEFAULT_PATH ) + endif() + if( NOT CUDA_VC_VARS_ALL_BAT ) + message(FATAL_ERROR "Cannot find path to vcvarsall.bat. Looked in ${CUDA_VS_DIR}/VC/bin ${CUDA_VS_DIR}/VC/Auxiliary/Build") + endif() + #message("CUDA_VS_DIR = ${CUDA_VS_DIR}, CUDA_VC_VARS_ALL_BAT = ${CUDA_VC_VARS_ALL_BAT}") +endif() + +# Propagate the host flags to the host compiler via -Xcompiler +option(CUDA_PROPAGATE_HOST_FLAGS "Propage C/CXX_FLAGS and friends to the host compiler via -Xcompile" ON) + +# Enable CUDA_SEPARABLE_COMPILATION +option(CUDA_SEPARABLE_COMPILATION "Compile CUDA objects with separable compilation enabled. Requires CUDA 5.0+" OFF) + +# Specifies whether the commands used when compiling the .cu file will be printed out. +option(CUDA_VERBOSE_BUILD "Print out the commands run while compiling the CUDA source file. With the Makefile generator this defaults to VERBOSE variable specified on the command line, but can be forced on with this option." OFF) + +mark_as_advanced( + CUDA_64_BIT_DEVICE_CODE + CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE + CUDA_GENERATED_OUTPUT_DIR + CUDA_HOST_COMPILATION_CPP + CUDA_NVCC_FLAGS + CUDA_PROPAGATE_HOST_FLAGS + CUDA_BUILD_CUBIN + CUDA_BUILD_EMULATION + CUDA_VERBOSE_BUILD + CUDA_SEPARABLE_COMPILATION + ) + +# Makefile and similar generators don't define CMAKE_CONFIGURATION_TYPES, so we +# need to add another entry for the CMAKE_BUILD_TYPE. We also need to add the +# standerd set of 4 build types (Debug, MinSizeRel, Release, and RelWithDebInfo) +# for completeness. We need run this loop in order to accomodate the addition +# of extra configuration types. Duplicate entries will be removed by +# REMOVE_DUPLICATES. +set(CUDA_configuration_types ${CMAKE_CONFIGURATION_TYPES} ${CMAKE_BUILD_TYPE} Debug MinSizeRel Release RelWithDebInfo) +list(REMOVE_DUPLICATES CUDA_configuration_types) +foreach(config ${CUDA_configuration_types}) + string(TOUPPER ${config} config_upper) + set(CUDA_NVCC_FLAGS_${config_upper} "" CACHE STRING "Semi-colon delimit multiple arguments.") + mark_as_advanced(CUDA_NVCC_FLAGS_${config_upper}) +endforeach() + +############################################################################### +############################################################################### +# Locate CUDA, Set Build Type, etc. +############################################################################### +############################################################################### + +macro(cuda_unset_include_and_libraries) + unset(CUDA_TOOLKIT_INCLUDE CACHE) + unset(CUDA_CUDART_LIBRARY CACHE) + unset(CUDA_CUDA_LIBRARY CACHE) + # Make sure you run this before you unset CUDA_VERSION. + if(CUDA_VERSION VERSION_EQUAL "3.0") + # This only existed in the 3.0 version of the CUDA toolkit + unset(CUDA_CUDARTEMU_LIBRARY CACHE) + endif() + if( DEFINED CUDA_NVASM_EXECUTABLE ) + unset(CUDA_NVASM_EXECUTABLE) + endif() + if( DEFINED CUDA_FATBINARY_EXECUTABLE ) + unset(CUDA_FATBINARY_EXECUTABLE) + endif() + unset(CUDA_cudart_static_LIBRARY CACHE) + unset(CUDA_cudadevrt_LIBRARY CACHE) + unset(CUDA_cublas_LIBRARY CACHE) + unset(CUDA_cublas_device_LIBRARY CACHE) + unset(CUDA_cublasemu_LIBRARY CACHE) + unset(CUDA_cufft_LIBRARY CACHE) + unset(CUDA_cufftemu_LIBRARY CACHE) + unset(CUDA_cupti_LIBRARY CACHE) + unset(CUDA_curand_LIBRARY CACHE) + unset(CUDA_cusolver_LIBRARY CACHE) + unset(CUDA_cusparse_LIBRARY CACHE) + unset(CUDA_npp_LIBRARY CACHE) + unset(CUDA_nppc_LIBRARY CACHE) + unset(CUDA_nppi_LIBRARY CACHE) + unset(CUDA_npps_LIBRARY CACHE) + unset(CUDA_nvcuvenc_LIBRARY CACHE) + unset(CUDA_nvcuvid_LIBRARY CACHE) + unset(CUDA_nvrtc_LIBRARY CACHE) + unset(CUDA_USE_STATIC_CUDA_RUNTIME CACHE) + unset(CUDA_GPU_DETECT_OUTPUT CACHE) +endmacro() + +# Check to see if the CUDA_TOOLKIT_ROOT_DIR and CUDA_SDK_ROOT_DIR have changed, +# if they have then clear the cache variables, so that will be detected again. +if(NOT "${CUDA_TOOLKIT_ROOT_DIR}" STREQUAL "${CUDA_TOOLKIT_ROOT_DIR_INTERNAL}") + unset(CUDA_TOOLKIT_TARGET_DIR CACHE) + unset(CUDA_NVCC_EXECUTABLE CACHE) + cuda_unset_include_and_libraries() + unset(CUDA_VERSION CACHE) +endif() + +if(NOT "${CUDA_TOOLKIT_TARGET_DIR}" STREQUAL "${CUDA_TOOLKIT_TARGET_DIR_INTERNAL}") + cuda_unset_include_and_libraries() +endif() + +# +# End of unset() +# + +# +# Start looking for things +# + +# Search for the cuda distribution. +if(NOT CUDA_TOOLKIT_ROOT_DIR AND NOT CMAKE_CROSSCOMPILING) + # Search in the CUDA_BIN_PATH first. + find_path(CUDA_TOOLKIT_ROOT_DIR + NAMES nvcc nvcc.exe + PATHS + ENV CUDA_TOOLKIT_ROOT + ENV CUDA_PATH + ENV CUDA_BIN_PATH + PATH_SUFFIXES bin bin64 + DOC "Toolkit location." + NO_DEFAULT_PATH + ) + + # Now search default paths + find_path(CUDA_TOOLKIT_ROOT_DIR + NAMES nvcc nvcc.exe + PATHS /opt/cuda/bin + /usr/local/bin + /usr/local/cuda/bin + DOC "Toolkit location." + ) + + if (CUDA_TOOLKIT_ROOT_DIR) + string(REGEX REPLACE "[/\\\\]?bin[64]*[/\\\\]?$" "" CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR}) + # We need to force this back into the cache. + set(CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT_DIR} CACHE PATH "Toolkit location." FORCE) + set(CUDA_TOOLKIT_TARGET_DIR ${CUDA_TOOLKIT_ROOT_DIR}) + endif() + + if (NOT EXISTS ${CUDA_TOOLKIT_ROOT_DIR}) + if(CUDA_FIND_REQUIRED) + message(FATAL_ERROR "Specify CUDA_TOOLKIT_ROOT_DIR") + elseif(NOT CUDA_FIND_QUIETLY) + message("CUDA_TOOLKIT_ROOT_DIR not found or specified") + endif() + endif () +endif () + +if(CMAKE_CROSSCOMPILING) + SET (CUDA_TOOLKIT_ROOT $ENV{CUDA_TOOLKIT_ROOT}) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "armv7-a") + # Support for NVPACK + set (CUDA_TOOLKIT_TARGET_NAME "armv7-linux-androideabi") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") + # Support for arm cross compilation + set(CUDA_TOOLKIT_TARGET_NAME "armv7-linux-gnueabihf") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64") + # Support for aarch64 cross compilation + if (ANDROID_ARCH_NAME STREQUAL "arm64") + set(CUDA_TOOLKIT_TARGET_NAME "aarch64-linux-androideabi") + else() + set(CUDA_TOOLKIT_TARGET_NAME "aarch64-linux") + endif (ANDROID_ARCH_NAME STREQUAL "arm64") + endif() + + if (EXISTS "${CUDA_TOOLKIT_ROOT}/targets/${CUDA_TOOLKIT_TARGET_NAME}") + set(CUDA_TOOLKIT_TARGET_DIR "${CUDA_TOOLKIT_ROOT}/targets/${CUDA_TOOLKIT_TARGET_NAME}" CACHE PATH "CUDA Toolkit target location.") + SET (CUDA_TOOLKIT_ROOT_DIR ${CUDA_TOOLKIT_ROOT}) + mark_as_advanced(CUDA_TOOLKIT_TARGET_DIR) + endif() + + # add known CUDA targetr root path to the set of directories we search for programs, libraries and headers + set( CMAKE_FIND_ROOT_PATH "${CUDA_TOOLKIT_TARGET_DIR};${CMAKE_FIND_ROOT_PATH}") + macro( cuda_find_host_program ) + find_host_program( ${ARGN} ) + endmacro() +else() + # for non-cross-compile, find_host_program == find_program and CUDA_TOOLKIT_TARGET_DIR == CUDA_TOOLKIT_ROOT_DIR + macro( cuda_find_host_program ) + find_program( ${ARGN} ) + endmacro() + set(_CUDA_TOOLKIT_ROOT_DIR_CMAKE "${CUDA_TOOLKIT_ROOT_DIR}") + file(TO_CMAKE_PATH "${_CUDA_TOOLKIT_ROOT_DIR_CMAKE}" _CUDA_TOOLKIT_ROOT_DIR_CMAKE) +endif() + + +# CUDA_NVCC_EXECUTABLE +cuda_find_host_program(CUDA_NVCC_EXECUTABLE + NAMES nvcc + PATHS "${_CUDA_TOOLKIT_ROOT_DIR_CMAKE}" + ENV CUDA_PATH + ENV CUDA_BIN_PATH + PATH_SUFFIXES bin bin64 + NO_DEFAULT_PATH + ) +# Search default search paths, after we search our own set of paths. +cuda_find_host_program(CUDA_NVCC_EXECUTABLE nvcc) +mark_as_advanced(CUDA_NVCC_EXECUTABLE) + +# CUDA_NVASM_EXECUTABLE +cuda_find_host_program(CUDA_NVASM_EXECUTABLE + NAMES nvasm_internal + PATHS "${_CUDA_TOOLKIT_ROOT_DIR_CMAKE}" + ENV CUDA_PATH + ENV CUDA_BIN_PATH + PATH_SUFFIXES bin bin64 + NO_DEFAULT_PATH + ) +# Search default search paths, after we search our own set of paths. +cuda_find_host_program(CUDA_NVASM_EXECUTABLE nvasm_internal) +mark_as_advanced(CUDA_NVASM_EXECUTABLE) + + +# Find fatbinary from CUDA +cuda_find_host_program(CUDA_FATBINARY_EXECUTABLE + NAMES fatbinary + PATHS "${_CUDA_TOOLKIT_ROOT_DIR_CMAKE}" + ENV CUDA_PATH + ENV CUDA_BIN_PATH + PATH_SUFFIXES bin bin64 + NO_DEFAULT_PATH + ) +# Search default search paths, after we search our own set of paths. +cuda_find_host_program(CUDA_FATBINARY_EXECUTABLE fatbinary) +mark_as_advanced(CUDA_FATBINARY_EXECUTABLE) + + +if(CUDA_NVCC_EXECUTABLE AND NOT CUDA_VERSION) + # Compute the version. + execute_process (COMMAND ${CUDA_NVCC_EXECUTABLE} "--version" OUTPUT_VARIABLE NVCC_OUT) + string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\1" CUDA_VERSION_MAJOR ${NVCC_OUT}) + string(REGEX REPLACE ".*release ([0-9]+)\\.([0-9]+).*" "\\2" CUDA_VERSION_MINOR ${NVCC_OUT}) + set(CUDA_VERSION "${CUDA_VERSION_MAJOR}.${CUDA_VERSION_MINOR}" CACHE STRING "Version of CUDA as computed from nvcc.") + mark_as_advanced(CUDA_VERSION) +else() + # Need to set these based off of the cached value + string(REGEX REPLACE "([0-9]+)\\.([0-9]+).*" "\\1" CUDA_VERSION_MAJOR "${CUDA_VERSION}") + string(REGEX REPLACE "([0-9]+)\\.([0-9]+).*" "\\2" CUDA_VERSION_MINOR "${CUDA_VERSION}") +endif() + +# Always set this convenience variable +set(CUDA_VERSION_STRING "${CUDA_VERSION}") + +# Here we need to determine if the version we found is acceptable. We will +# assume that is unless CUDA_FIND_VERSION_EXACT or CUDA_FIND_VERSION is +# specified. The presence of either of these options checks the version +# string and signals if the version is acceptable or not. +set(_cuda_version_acceptable TRUE) +# +if(CUDA_FIND_VERSION_EXACT AND NOT CUDA_VERSION VERSION_EQUAL CUDA_FIND_VERSION) + set(_cuda_version_acceptable FALSE) +endif() +# +if(CUDA_FIND_VERSION AND CUDA_VERSION VERSION_LESS CUDA_FIND_VERSION) + set(_cuda_version_acceptable FALSE) +endif() +# +if(NOT _cuda_version_acceptable) + set(_cuda_error_message "Requested CUDA version ${CUDA_FIND_VERSION}, but found unacceptable version ${CUDA_VERSION}") + if(CUDA_FIND_REQUIRED) + message("${_cuda_error_message}") + elseif(NOT CUDA_FIND_QUIETLY) + message("${_cuda_error_message}") + endif() +endif() + +# CUDA_TOOLKIT_INCLUDE +find_path(CUDA_TOOLKIT_INCLUDE + device_functions.h # Header included in toolkit + PATHS ${CUDA_TOOLKIT_TARGET_DIR} + ENV CUDA_PATH + ENV CUDA_INC_PATH + PATH_SUFFIXES include + NO_DEFAULT_PATH + ) +# Search default search paths, after we search our own set of paths. +find_path(CUDA_TOOLKIT_INCLUDE device_functions.h) +mark_as_advanced(CUDA_TOOLKIT_INCLUDE) + +if (CUDA_VERSION VERSION_GREATER "7.0" OR EXISTS "${CUDA_TOOLKIT_INCLUDE}/cuda_fp16.h") + set(CUDA_HAS_FP16 TRUE) +else() + set(CUDA_HAS_FP16 FALSE) +endif() + +# Set the user list of include dir to nothing to initialize it. +set (CUDA_NVCC_INCLUDE_ARGS_USER "") +set (CUDA_INCLUDE_DIRS ${CUDA_TOOLKIT_INCLUDE}) + +macro(cuda_find_library_local_first_with_path_ext _var _names _doc _path_ext ) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + # CUDA 3.2+ on Windows moved the library directories, so we need the new + # and old paths. + set(_cuda_64bit_lib_dir "${_path_ext}lib/x64" "${_path_ext}lib64" "${_path_ext}libx64" ) + endif() + # CUDA 3.2+ on Windows moved the library directories, so we need to new + # (lib/Win32) and the old path (lib). + find_library(${_var} + NAMES ${_names} + PATHS "${CUDA_TOOLKIT_TARGET_DIR}" + ENV CUDA_PATH + ENV CUDA_LIB_PATH + PATH_SUFFIXES ${_cuda_64bit_lib_dir} "${_path_ext}lib/Win32" "${_path_ext}lib" "${_path_ext}libWin32" + DOC ${_doc} + NO_DEFAULT_PATH + ) + if (NOT CMAKE_CROSSCOMPILING) + # Search default search paths, after we search our own set of paths. + find_library(${_var} + NAMES ${_names} + PATHS "/usr/lib/nvidia-current" + DOC ${_doc} + ) + endif() +endmacro() + +macro(cuda_find_library_local_first _var _names _doc) + cuda_find_library_local_first_with_path_ext( "${_var}" "${_names}" "${_doc}" "" ) +endmacro() + +macro(find_library_local_first _var _names _doc ) + cuda_find_library_local_first( "${_var}" "${_names}" "${_doc}" "" ) +endmacro() + + +# CUDA_LIBRARIES +cuda_find_library_local_first(CUDA_CUDART_LIBRARY cudart "\"cudart\" library") +if(CUDA_VERSION VERSION_EQUAL "3.0") + # The cudartemu library only existed for the 3.0 version of CUDA. + cuda_find_library_local_first(CUDA_CUDARTEMU_LIBRARY cudartemu "\"cudartemu\" library") + mark_as_advanced( + CUDA_CUDARTEMU_LIBRARY + ) +endif() + +if(NOT CUDA_VERSION VERSION_LESS "5.5") + cuda_find_library_local_first(CUDA_cudart_static_LIBRARY cudart_static "static CUDA runtime library") + mark_as_advanced(CUDA_cudart_static_LIBRARY) +endif() + + +if(CUDA_cudart_static_LIBRARY) + # If static cudart available, use it by default, but provide a user-visible option to disable it. + option(CUDA_USE_STATIC_CUDA_RUNTIME "Use the static version of the CUDA runtime library if available" ON) + set(CUDA_CUDART_LIBRARY_VAR CUDA_cudart_static_LIBRARY) +else() + # If not available, silently disable the option. + set(CUDA_USE_STATIC_CUDA_RUNTIME OFF CACHE INTERNAL "") + set(CUDA_CUDART_LIBRARY_VAR CUDA_CUDART_LIBRARY) +endif() + +if(NOT CUDA_VERSION VERSION_LESS "5.0") + cuda_find_library_local_first(CUDA_cudadevrt_LIBRARY cudadevrt "\"cudadevrt\" library") + mark_as_advanced(CUDA_cudadevrt_LIBRARY) +endif() + +if(CUDA_USE_STATIC_CUDA_RUNTIME) + if(UNIX) + # Check for the dependent libraries. Here we look for pthreads. + if (DEFINED CMAKE_THREAD_PREFER_PTHREAD) + set(_cuda_cmake_thread_prefer_pthread ${CMAKE_THREAD_PREFER_PTHREAD}) + endif() + set(CMAKE_THREAD_PREFER_PTHREAD 1) + + # Many of the FindXYZ CMake comes with makes use of try_compile with int main(){return 0;} + # as the source file. Unfortunately this causes a warning with -Wstrict-prototypes and + # -Werror causes the try_compile to fail. We will just temporarily disable other flags + # when doing the find_package command here. + set(_cuda_cmake_c_flags ${CMAKE_C_FLAGS}) + set(CMAKE_C_FLAGS "-fPIC") + find_package(Threads REQUIRED) + set(CMAKE_C_FLAGS ${_cuda_cmake_c_flags}) + + if (DEFINED _cuda_cmake_thread_prefer_pthread) + set(CMAKE_THREAD_PREFER_PTHREAD ${_cuda_cmake_thread_prefer_pthread}) + unset(_cuda_cmake_thread_prefer_pthread) + else() + unset(CMAKE_THREAD_PREFER_PTHREAD) + endif() + if (NOT APPLE) + #On Linux, you must link against librt when using the static cuda runtime. + find_library(CUDA_rt_LIBRARY rt) + # CMake has a CMAKE_DL_LIBS, but I'm not sure what version of CMake provides this + find_library(CUDA_dl_LIBRARY dl) + if (NOT CUDA_rt_LIBRARY) + message(WARNING "Expecting to find librt for libcudart_static, but didn't find it.") + endif() + if (NOT CUDA_dl_LIBRARY) + message(WARNING "Expecting to find libdl for libcudart_static, but didn't find it.") + endif() + endif() + endif() +endif() + +# CUPTI library showed up in cuda toolkit 4.0 +if(NOT CUDA_VERSION VERSION_LESS "4.0") + cuda_find_library_local_first_with_path_ext(CUDA_cupti_LIBRARY cupti "\"cupti\" library" "extras/CUPTI/") + mark_as_advanced(CUDA_cupti_LIBRARY) +endif() + +# Set the CUDA_LIBRARIES variable. This is the set of stuff to link against if you are +# using the CUDA runtime. For the dynamic version of the runtime, most of the +# dependencies are brough in, but for the static version there are additional libraries +# and linker commands needed. +# Initialize to empty +set(CUDA_LIBRARIES) + +if(APPLE) + # We need to add the path to cudart to the linker using rpath, since the library name + # for the cuda libraries is prepended with @rpath. We need to add the path to the + # toolkit before we add the path to the driver below, so that we find our toolkit's code + # first. + if(CUDA_BUILD_EMULATION AND CUDA_CUDARTEMU_LIBRARY) + get_filename_component(_cuda_path_to_cudart "${CUDA_CUDARTEMU_LIBRARY}" PATH) + else() + get_filename_component(_cuda_path_to_cudart "${CUDA_CUDART_LIBRARY}" PATH) + endif() + if(_cuda_path_to_cudart) + list(APPEND CUDA_LIBRARIES -Wl,-rpath "-Wl,${_cuda_path_to_cudart}") + endif() +endif() + +# If we are using emulation mode and we found the cudartemu library then use +# that one instead of cudart. +if(CUDA_BUILD_EMULATION AND CUDA_CUDARTEMU_LIBRARY) + list(APPEND CUDA_LIBRARIES ${CUDA_CUDARTEMU_LIBRARY}) +elseif(CUDA_USE_STATIC_CUDA_RUNTIME AND CUDA_cudart_static_LIBRARY) + list(APPEND CUDA_LIBRARIES ${CUDA_cudart_static_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) + if (CUDA_rt_LIBRARY) + list(APPEND CUDA_LIBRARIES ${CUDA_rt_LIBRARY}) + endif() + if (CUDA_dl_LIBRARY) + list(APPEND CUDA_LIBRARIES ${CUDA_dl_LIBRARY}) + endif() + if(APPLE) + # We need to add the default path to the driver (libcuda.dylib) as an rpath, so that + # the static cuda runtime can find it at runtime. + list(APPEND CUDA_LIBRARIES -Wl,-rpath,/usr/local/cuda/lib) + endif() +else() + list(APPEND CUDA_LIBRARIES ${CUDA_CUDART_LIBRARY}) +endif() + +# 1.1 toolkit on linux doesn't appear to have a separate library on +# some platforms. +cuda_find_library_local_first(CUDA_CUDA_LIBRARY cuda "\"cuda\" library (older versions only).") + +mark_as_advanced( + CUDA_CUDA_LIBRARY + CUDA_CUDART_LIBRARY + ) + +####################### +# Look for some of the toolkit helper libraries +macro(FIND_CUDA_HELPER_LIBS _name) + cuda_find_library_local_first(CUDA_${_name}_LIBRARY ${_name} "\"${_name}\" library") + mark_as_advanced(CUDA_${_name}_LIBRARY) +endmacro() + +####################### +# Disable emulation for v3.1 onward +if(CUDA_VERSION VERSION_GREATER "3.0") + if(CUDA_BUILD_EMULATION) + message(FATAL_ERROR "CUDA_BUILD_EMULATION is not supported in version 3.1 and onwards. You must disable it to proceed. You have version ${CUDA_VERSION}.") + endif() +endif() + +# Search for additional CUDA toolkit libraries. +if(CUDA_VERSION VERSION_LESS "3.1") + # Emulation libraries aren't available in version 3.1 onward. + find_cuda_helper_libs(cufftemu) + find_cuda_helper_libs(cublasemu) +endif() +find_cuda_helper_libs(cufft) +find_cuda_helper_libs(cublas) +if(NOT CUDA_VERSION VERSION_LESS "3.2") + # cusparse showed up in version 3.2 + find_cuda_helper_libs(cusparse) + find_cuda_helper_libs(curand) + if (WIN32) + find_cuda_helper_libs(nvcuvenc) + find_cuda_helper_libs(nvcuvid) + endif() +endif() +if(CUDA_VERSION VERSION_GREATER "5.0") + find_cuda_helper_libs(cublas_device) + # In CUDA 5.5 NPP was splitted onto 3 separate libraries. + find_cuda_helper_libs(nppc) + find_cuda_helper_libs(nppi) + find_cuda_helper_libs(npps) + set(CUDA_npp_LIBRARY "${CUDA_nppc_LIBRARY};${CUDA_nppi_LIBRARY};${CUDA_npps_LIBRARY}") +elseif(NOT CUDA_VERSION VERSION_LESS "4.0") + find_cuda_helper_libs(npp) +endif() +if(NOT CUDA_VERSION VERSION_LESS "7.0") + # cusolver showed up in version 7.0 + find_cuda_helper_libs(cusolver) +endif() +if(NOT CUDA_VERSION VERSION_LESS "7.5") + find_cuda_helper_libs(nvrtc) +endif() + +if (CUDA_BUILD_EMULATION) + set(CUDA_CUFFT_LIBRARIES ${CUDA_cufftemu_LIBRARY}) + set(CUDA_CUBLAS_LIBRARIES ${CUDA_cublasemu_LIBRARY}) +else() + set(CUDA_CUFFT_LIBRARIES ${CUDA_cufft_LIBRARY}) + set(CUDA_CUBLAS_LIBRARIES ${CUDA_cublas_LIBRARY} ${CUDA_cublas_device_LIBRARY}) +endif() + +######################## +# Look for the SDK stuff. As of CUDA 3.0 NVSDKCUDA_ROOT has been replaced with +# NVSDKCOMPUTE_ROOT with the old CUDA C contents moved into the C subdirectory +find_path(CUDA_SDK_ROOT_DIR common/inc/cutil.h + HINTS + "$ENV{NVSDKCOMPUTE_ROOT}/C" + ENV NVSDKCUDA_ROOT + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\NVIDIA Corporation\\Installed Products\\NVIDIA SDK 10\\Compute;InstallDir]" + PATHS + "/Developer/GPU\ Computing/C" + ) + +# Keep the CUDA_SDK_ROOT_DIR first in order to be able to override the +# environment variables. +set(CUDA_SDK_SEARCH_PATH + "${CUDA_SDK_ROOT_DIR}" + "${CUDA_TOOLKIT_ROOT_DIR}/local/NVSDK0.2" + "${CUDA_TOOLKIT_ROOT_DIR}/NVSDK0.2" + "${CUDA_TOOLKIT_ROOT_DIR}/NV_CUDA_SDK" + "$ENV{HOME}/NVIDIA_CUDA_SDK" + "$ENV{HOME}/NVIDIA_CUDA_SDK_MACOSX" + "/Developer/CUDA" + ) + +# Example of how to find an include file from the CUDA_SDK_ROOT_DIR + +# find_path(CUDA_CUT_INCLUDE_DIR +# cutil.h +# PATHS ${CUDA_SDK_SEARCH_PATH} +# PATH_SUFFIXES "common/inc" +# DOC "Location of cutil.h" +# NO_DEFAULT_PATH +# ) +# # Now search system paths +# find_path(CUDA_CUT_INCLUDE_DIR cutil.h DOC "Location of cutil.h") + +# mark_as_advanced(CUDA_CUT_INCLUDE_DIR) + + +# Example of how to find a library in the CUDA_SDK_ROOT_DIR + +# # cutil library is called cutil64 for 64 bit builds on windows. We don't want +# # to get these confused, so we are setting the name based on the word size of +# # the build. + +# if(CMAKE_SIZEOF_VOID_P EQUAL 8) +# set(cuda_cutil_name cutil64) +# else() +# set(cuda_cutil_name cutil32) +# endif() + +# find_library(CUDA_CUT_LIBRARY +# NAMES cutil ${cuda_cutil_name} +# PATHS ${CUDA_SDK_SEARCH_PATH} +# # The new version of the sdk shows up in common/lib, but the old one is in lib +# PATH_SUFFIXES "common/lib" "lib" +# DOC "Location of cutil library" +# NO_DEFAULT_PATH +# ) +# # Now search system paths +# find_library(CUDA_CUT_LIBRARY NAMES cutil ${cuda_cutil_name} DOC "Location of cutil library") +# mark_as_advanced(CUDA_CUT_LIBRARY) +# set(CUDA_CUT_LIBRARIES ${CUDA_CUT_LIBRARY}) + + + +############################# +# Check for required components +set(CUDA_FOUND TRUE) + +set(CUDA_TOOLKIT_ROOT_DIR_INTERNAL "${CUDA_TOOLKIT_ROOT_DIR}" CACHE INTERNAL + "This is the value of the last time CUDA_TOOLKIT_ROOT_DIR was set successfully." FORCE) +set(CUDA_TOOLKIT_TARGET_DIR_INTERNAL "${CUDA_TOOLKIT_TARGET_DIR}" CACHE INTERNAL + "This is the value of the last time CUDA_TOOLKIT_TARGET_DIR was set successfully." FORCE) +set(CUDA_SDK_ROOT_DIR_INTERNAL "${CUDA_SDK_ROOT_DIR}" CACHE INTERNAL + "This is the value of the last time CUDA_SDK_ROOT_DIR was set successfully." FORCE) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CUDA + REQUIRED_VARS + CUDA_TOOLKIT_ROOT_DIR + CUDA_NVCC_EXECUTABLE + CUDA_INCLUDE_DIRS + ${CUDA_CUDART_LIBRARY_VAR} + VERSION_VAR + CUDA_VERSION + ) + + + +############################################################################### +############################################################################### +# Macros +############################################################################### +############################################################################### + +############################################################################### +# Add include directories to pass to the nvcc command. +macro(CUDA_INCLUDE_DIRECTORIES) + foreach(dir ${ARGN}) + list(APPEND CUDA_NVCC_INCLUDE_ARGS_USER -I${dir}) + endforeach() +endmacro() + + +############################################################################## +cuda_find_helper_file(parse_cubin cmake) +cuda_find_helper_file(make2cmake cmake) +cuda_find_helper_file(run_nvcc cmake) +include("${CMAKE_CURRENT_LIST_DIR}/FindCUDA/select_compute_arch.cmake") + +############################################################################## +# Separate the OPTIONS out from the sources +# +macro(CUDA_GET_SOURCES_AND_OPTIONS _sources _cmake_options _options) + set( ${_sources} ) + set( ${_cmake_options} ) + set( ${_options} ) + set( _found_options FALSE ) + foreach(arg ${ARGN}) + if("x${arg}" STREQUAL "xOPTIONS") + set( _found_options TRUE ) + elseif( + "x${arg}" STREQUAL "xWIN32" OR + "x${arg}" STREQUAL "xMACOSX_BUNDLE" OR + "x${arg}" STREQUAL "xEXCLUDE_FROM_ALL" OR + "x${arg}" STREQUAL "xSTATIC" OR + "x${arg}" STREQUAL "xSHARED" OR + "x${arg}" STREQUAL "xMODULE" + ) + list(APPEND ${_cmake_options} ${arg}) + else() + if ( _found_options ) + list(APPEND ${_options} ${arg}) + else() + # Assume this is a file + list(APPEND ${_sources} ${arg}) + endif() + endif() + endforeach() +endmacro() + +############################################################################## +# Parse the OPTIONS from ARGN and set the variables prefixed by _option_prefix +# +macro(CUDA_PARSE_NVCC_OPTIONS _option_prefix) + set( _found_config ) + foreach(arg ${ARGN}) + # Determine if we are dealing with a perconfiguration flag + foreach(config ${CUDA_configuration_types}) + string(TOUPPER ${config} config_upper) + if (arg STREQUAL "${config_upper}") + set( _found_config _${arg}) + # Set arg to nothing to keep it from being processed further + set( arg ) + endif() + endforeach() + + if ( arg ) + list(APPEND ${_option_prefix}${_found_config} "${arg}") + endif() + endforeach() +endmacro() + +############################################################################## +# Helper to add the include directory for CUDA only once +function(CUDA_ADD_CUDA_INCLUDE_ONCE) + get_directory_property(_include_directories INCLUDE_DIRECTORIES) + set(_add TRUE) + if(_include_directories) + foreach(dir ${_include_directories}) + if("${dir}" STREQUAL "${CUDA_INCLUDE_DIRS}") + set(_add FALSE) + endif() + endforeach() + endif() + if(_add) + include_directories(${CUDA_INCLUDE_DIRS}) + endif() +endfunction() + +function(CUDA_BUILD_SHARED_LIBRARY shared_flag) + set(cmake_args ${ARGN}) + # If SHARED, MODULE, or STATIC aren't already in the list of arguments, then + # add SHARED or STATIC based on the value of BUILD_SHARED_LIBS. + list(FIND cmake_args SHARED _cuda_found_SHARED) + list(FIND cmake_args MODULE _cuda_found_MODULE) + list(FIND cmake_args STATIC _cuda_found_STATIC) + if( _cuda_found_SHARED GREATER -1 OR + _cuda_found_MODULE GREATER -1 OR + _cuda_found_STATIC GREATER -1) + set(_cuda_build_shared_libs) + else() + if (BUILD_SHARED_LIBS) + set(_cuda_build_shared_libs SHARED) + else() + set(_cuda_build_shared_libs STATIC) + endif() + endif() + set(${shared_flag} ${_cuda_build_shared_libs} PARENT_SCOPE) +endfunction() + +############################################################################## +# Helper to avoid clashes of files with the same basename but different paths. +# This doesn't attempt to do exactly what CMake internals do, which is to only +# add this path when there is a conflict, since by the time a second collision +# in names is detected it's already too late to fix the first one. For +# consistency sake the relative path will be added to all files. +function(CUDA_COMPUTE_BUILD_PATH path build_path) + #message("CUDA_COMPUTE_BUILD_PATH([${path}] ${build_path})") + # Only deal with CMake style paths from here on out + file(TO_CMAKE_PATH "${path}" bpath) + if (IS_ABSOLUTE "${bpath}") + # Absolute paths are generally unnessary, especially if something like + # file(GLOB_RECURSE) is used to pick up the files. + + string(FIND "${bpath}" "${CMAKE_CURRENT_BINARY_DIR}" _binary_dir_pos) + if (_binary_dir_pos EQUAL 0) + file(RELATIVE_PATH bpath "${CMAKE_CURRENT_BINARY_DIR}" "${bpath}") + else() + file(RELATIVE_PATH bpath "${CMAKE_CURRENT_SOURCE_DIR}" "${bpath}") + endif() + endif() + + # This recipe is from cmLocalGenerator::CreateSafeUniqueObjectFileName in the + # CMake source. + + # Remove leading / + string(REGEX REPLACE "^[/]+" "" bpath "${bpath}") + # Avoid absolute paths by removing ':' + string(REPLACE ":" "_" bpath "${bpath}") + # Avoid relative paths that go up the tree + string(REPLACE "../" "__/" bpath "${bpath}") + # Avoid spaces + string(REPLACE " " "_" bpath "${bpath}") + + # Strip off the filename. I wait until here to do it, since removin the + # basename can make a path that looked like path/../basename turn into + # path/.. (notice the trailing slash). + get_filename_component(bpath "${bpath}" PATH) + + set(${build_path} "${bpath}" PARENT_SCOPE) + #message("${build_path} = ${bpath}") +endfunction() + +############################################################################## +############################################################################## +# CUDA WRAP SRCS +# +# This helper macro populates the following variables and setups up custom +# commands and targets to invoke the nvcc compiler to generate C or PTX source +# dependent upon the format parameter. The compiler is invoked once with -M +# to generate a dependency file and a second time with -cuda or -ptx to generate +# a .cpp or .ptx file. +# INPUT: +# cuda_target - Target name +# format - PTX, CUBIN, FATBIN or OBJ +# FILE1 .. FILEN - The remaining arguments are the sources to be wrapped. +# OPTIONS - Extra options to NVCC +# OUTPUT: +# generated_files - List of generated files +############################################################################## +############################################################################## + +macro(CUDA_WRAP_SRCS cuda_target format generated_files) + + # If CMake doesn't support separable compilation, complain + if(CUDA_SEPARABLE_COMPILATION AND CMAKE_VERSION VERSION_LESS "2.8.10.1") + message(SEND_ERROR "CUDA_SEPARABLE_COMPILATION isn't supported for CMake versions less than 2.8.10.1") + endif() + + # Set up all the command line flags here, so that they can be overridden on a per target basis. + + set(nvcc_flags "") + + # Emulation if the card isn't present. + if (CUDA_BUILD_EMULATION) + # Emulation. + set(nvcc_flags ${nvcc_flags} --device-emulation -D_DEVICEEMU -g) + else() + # Device mode. No flags necessary. + endif() + + if(CUDA_HOST_COMPILATION_CPP) + set(CUDA_C_OR_CXX CXX) + else() + if(CUDA_VERSION VERSION_LESS "3.0") + set(nvcc_flags ${nvcc_flags} --host-compilation C) + else() + message(WARNING "--host-compilation flag is deprecated in CUDA version >= 3.0. Removing --host-compilation C flag" ) + endif() + set(CUDA_C_OR_CXX C) + endif() + + set(generated_extension ${CMAKE_${CUDA_C_OR_CXX}_OUTPUT_EXTENSION}) + + if(CUDA_64_BIT_DEVICE_CODE) + set(nvcc_flags ${nvcc_flags} -m64) + else() + set(nvcc_flags ${nvcc_flags} -m32) + endif() + + if(CUDA_TARGET_CPU_ARCH) + set(nvcc_flags ${nvcc_flags} "--target-cpu-architecture=${CUDA_TARGET_CPU_ARCH}") + endif() + + # This needs to be passed in at this stage, because VS needs to fill out the + # value of VCInstallDir from within VS. Note that CCBIN is only used if + # -ccbin or --compiler-bindir isn't used and CUDA_HOST_COMPILER matches + # $(VCInstallDir)/bin. + if(CMAKE_GENERATOR MATCHES "Visual Studio") + set(ccbin_flags -D "\"CCBIN:PATH=${CUDA_HOST_COMPILER}\"" ) + else() + set(ccbin_flags) + endif() + + # Figure out which configure we will use and pass that in as an argument to + # the script. We need to defer the decision until compilation time, because + # for VS projects we won't know if we are making a debug or release build + # until build time. + if(CMAKE_GENERATOR MATCHES "Visual Studio") + set( CUDA_build_configuration "$(ConfigurationName)" ) + else() + set( CUDA_build_configuration "${CMAKE_BUILD_TYPE}") + endif() + + # Initialize our list of includes with the user ones followed by the CUDA system ones. + set(CUDA_NVCC_INCLUDE_ARGS ${CUDA_NVCC_INCLUDE_ARGS_USER} "-I${CUDA_INCLUDE_DIRS}") + # Get the include directories for this directory and use them for our nvcc command. + get_directory_property(CUDA_NVCC_INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES) + if(CUDA_NVCC_INCLUDE_DIRECTORIES) + foreach(dir ${CUDA_NVCC_INCLUDE_DIRECTORIES}) + list(APPEND CUDA_NVCC_INCLUDE_ARGS -I${dir}) + endforeach() + endif() + + # Reset these variables + set(CUDA_WRAP_OPTION_NVCC_FLAGS) + foreach(config ${CUDA_configuration_types}) + string(TOUPPER ${config} config_upper) + set(CUDA_WRAP_OPTION_NVCC_FLAGS_${config_upper}) + endforeach() + + CUDA_GET_SOURCES_AND_OPTIONS(_cuda_wrap_sources _cuda_wrap_cmake_options _cuda_wrap_options ${ARGN}) + CUDA_PARSE_NVCC_OPTIONS(CUDA_WRAP_OPTION_NVCC_FLAGS ${_cuda_wrap_options}) + + # Figure out if we are building a shared library. BUILD_SHARED_LIBS is + # respected in CUDA_ADD_LIBRARY. + set(_cuda_build_shared_libs FALSE) + # SHARED, MODULE + list(FIND _cuda_wrap_cmake_options SHARED _cuda_found_SHARED) + list(FIND _cuda_wrap_cmake_options MODULE _cuda_found_MODULE) + if(_cuda_found_SHARED GREATER -1 OR _cuda_found_MODULE GREATER -1) + set(_cuda_build_shared_libs TRUE) + endif() + # STATIC + list(FIND _cuda_wrap_cmake_options STATIC _cuda_found_STATIC) + if(_cuda_found_STATIC GREATER -1) + set(_cuda_build_shared_libs FALSE) + endif() + + # CUDA_HOST_FLAGS + if(_cuda_build_shared_libs) + # If we are setting up code for a shared library, then we need to add extra flags for + # compiling objects for shared libraries. + set(CUDA_HOST_SHARED_FLAGS ${CMAKE_SHARED_LIBRARY_${CUDA_C_OR_CXX}_FLAGS}) + else() + set(CUDA_HOST_SHARED_FLAGS) + endif() + + # If we are using batch building and we are using VS 2013+ we could have problems with + # parallel accesses to the PDB files which comes from the parallel batch building. /FS + # serializes the builds which fixes this. There doesn't seem any harm to add this for + # PTX targets or for builds that don't do parallel building. + set( EXTRA_FS_ARG ) + if( CUDA_BATCH_BUILD_LOG AND MSVC ) + if(NOT MSVC_VERSION VERSION_LESS 1800) + set( EXTRA_FS_ARG "/FS" ) + endif() + endif() + + + # Only add the CMAKE_{C,CXX}_FLAGS if we are propagating host flags. We + # always need to set the SHARED_FLAGS, though. + if(CUDA_PROPAGATE_HOST_FLAGS) + set(_cuda_host_flags "set(CMAKE_HOST_FLAGS ${CMAKE_${CUDA_C_OR_CXX}_FLAGS} ${CUDA_HOST_SHARED_FLAGS} ${EXTRA_FS_ARG})") + else() + set(_cuda_host_flags "set(CMAKE_HOST_FLAGS ${CUDA_HOST_SHARED_FLAGS} ${EXTRA_FS_ARG})") + endif() + + set(_cuda_nvcc_flags_config "# Build specific configuration flags") + # Loop over all the configuration types to generate appropriate flags for run_nvcc.cmake + foreach(config ${CUDA_configuration_types}) + string(TOUPPER ${config} config_upper) + # CMAKE_FLAGS are strings and not lists. By not putting quotes around CMAKE_FLAGS + # we convert the strings to lists (like we want). + + if(CUDA_PROPAGATE_HOST_FLAGS) + # nvcc chokes on -g3 in versions previous to 3.0, so replace it with -g + set(_cuda_fix_g3 FALSE) + + if(CMAKE_COMPILER_IS_GNUCC) + if (CUDA_VERSION VERSION_LESS "3.0" OR + CUDA_VERSION VERSION_EQUAL "4.1" OR + CUDA_VERSION VERSION_EQUAL "4.2" + ) + set(_cuda_fix_g3 TRUE) + endif() + endif() + if(_cuda_fix_g3) + string(REPLACE "-g3" "-g" _cuda_C_FLAGS "${CMAKE_${CUDA_C_OR_CXX}_FLAGS_${config_upper}}") + else() + set(_cuda_C_FLAGS "${CMAKE_${CUDA_C_OR_CXX}_FLAGS_${config_upper}}") + endif() + + # Using the optimized debug information flag causes problems. + if (MSVC) + string(REPLACE "/Zo" "" _cuda_C_FLAGS "${_cuda_C_FLAGS}") + endif() + + set(_cuda_host_flags "${_cuda_host_flags}\nset(CMAKE_HOST_FLAGS_${config_upper} ${_cuda_C_FLAGS})") + endif() + + # Note that if we ever want CUDA_NVCC_FLAGS_ to be string (instead of a list + # like it is currently), we can remove the quotes around the + # ${CUDA_NVCC_FLAGS_${config_upper}} variable like the CMAKE_HOST_FLAGS_ variable. + set(_cuda_nvcc_flags_config "${_cuda_nvcc_flags_config}\nset(CUDA_NVCC_FLAGS_${config_upper} ${CUDA_NVCC_FLAGS_${config_upper}} ;; ${CUDA_WRAP_OPTION_NVCC_FLAGS_${config_upper}})") + endforeach() + + # NVCC can't handle this C++ argument, because it uses during certain phases where the C + # compiler is invoked and complains about it. + if( CMAKE_COMPILER_IS_GNUCXX ) + string(REPLACE "-fvisibility-inlines-hidden" "" _cuda_host_flags "${_cuda_host_flags}") + endif() + + # Process the C++11 flag. If the host sets the flag, we need to add it to nvcc and + # remove it from the host. This is because -Xcompile -std=c++ will choke nvcc (it uses + # the C preprocessor). In order to get this to work correctly, we need to use nvcc's + # specific c++11 flag. + if( "${_cuda_host_flags}" MATCHES "-std=c\\+\\+11" OR ( CMAKE_CXX_STANDARD EQUAL 11 AND NOT USING_WINDOWS_CL ) ) + # Add the c++11 flag to nvcc if it isn't already present. Note that we only look at + # the main flag instead of the configuration specific flags. + if( NOT "${CUDA_NVCC_FLAGS}" MATCHES "-std;c\\+\\+11" ) + list(APPEND nvcc_flags --std c++11) + endif() + string(REGEX REPLACE "[-]+std=c\\+\\+11" "" _cuda_host_flags "${_cuda_host_flags}") + endif() + + # Get the list of definitions from the directory property + get_directory_property(CUDA_NVCC_DEFINITIONS COMPILE_DEFINITIONS) + if(CUDA_NVCC_DEFINITIONS) + foreach(_definition ${CUDA_NVCC_DEFINITIONS}) + list(APPEND nvcc_flags "-D${_definition}") + endforeach() + endif() + + if(_cuda_build_shared_libs) + list(APPEND nvcc_flags "-D${cuda_target}_EXPORTS") + endif() + + # Reset the output variable + set(_cuda_wrap_generated_files "") + + # Iterate over the macro arguments and create custom + # commands for all the .cu files. + foreach(file ${ARGN}) + # Ignore any file marked as a HEADER_FILE_ONLY + get_source_file_property(_is_header ${file} HEADER_FILE_ONLY) + # Allow per source file overrides of the format. Also allows compiling non-.cu files. + get_source_file_property(_cuda_source_format ${file} CUDA_SOURCE_PROPERTY_FORMAT) + if((${file} MATCHES "\\.cu$" OR _cuda_source_format) AND NOT _is_header) + + if(NOT _cuda_source_format) + set(_cuda_source_format ${format}) + endif() + # If file isn't a .cu file, we need to tell nvcc to treat it as such. + if(NOT ${file} MATCHES "\\.cu$") + set(cuda_language_flag -x=cu) + else() + set(cuda_language_flag) + endif() + + if( ${_cuda_source_format} MATCHES "OBJ") + set( cuda_compile_to_external_module OFF ) + else() + set( cuda_compile_to_external_module ON ) + if( ${_cuda_source_format} MATCHES "PTX" ) + set( cuda_compile_to_external_module_flag "-ptx") + set( cuda_compile_to_external_module_type "ptx" ) + elseif( ${_cuda_source_format} MATCHES "CUBIN") + set( cuda_compile_to_external_module_flag "-cubin" ) + set( cuda_compile_to_external_module_type "cubin" ) + elseif( ${_cuda_source_format} MATCHES "FATBIN") + set( cuda_compile_to_external_module_flag "-fatbin" ) + set( cuda_compile_to_external_module_type "fatbin" ) + else() + if(DEFINED CUDA_CUSTOM_SOURCE_FORMAT_FLAG_${_cuda_source_format} AND DEFINED CUDA_CUSTOM_SOURCE_FORMAT_TYPE_${_cuda_source_format}) + set( cuda_compile_to_external_module_flag "${CUDA_CUSTOM_SOURCE_FORMAT_FLAG_${_cuda_source_format}}" ) + set( cuda_compile_to_external_module_type "${CUDA_CUSTOM_SOURCE_FORMAT_TYPE_${_cuda_source_format}}" ) + else() + message( FATAL_ERROR "Invalid format flag passed to CUDA_WRAP_SRCS or set with CUDA_SOURCE_PROPERTY_FORMAT file property for file '${file}': '${_cuda_source_format}'. Use OBJ, PTX, CUBIN or FATBIN.") + endif() + endif() + endif() + + if(cuda_compile_to_external_module) + # Don't use any of the host compilation flags for PTX targets. + set(CUDA_HOST_FLAGS) + set(CUDA_NVCC_FLAGS_CONFIG) + else() + set(CUDA_HOST_FLAGS ${_cuda_host_flags}) + set(CUDA_NVCC_FLAGS_CONFIG ${_cuda_nvcc_flags_config}) + endif() + + # Determine output directory + cuda_compute_build_path("${file}" cuda_build_path) + set(cuda_compile_intermediate_directory "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${cuda_target}.dir/${cuda_build_path}") + if(CUDA_GENERATED_OUTPUT_DIR) + set(cuda_compile_output_dir "${CUDA_GENERATED_OUTPUT_DIR}") + else() + if ( cuda_compile_to_external_module ) + set(cuda_compile_output_dir "${CMAKE_CURRENT_BINARY_DIR}") + else() + set(cuda_compile_output_dir "${cuda_compile_intermediate_directory}") + endif() + endif() + + # Add a custom target to generate a c or ptx file. ###################### + + get_filename_component( basename ${file} NAME ) + if( cuda_compile_to_external_module ) + set(generated_file_path "${cuda_compile_output_dir}") + set(generated_file_basename "${cuda_target}_generated_${basename}.${cuda_compile_to_external_module_type}") + set(format_flag "${cuda_compile_to_external_module_flag}") + file(MAKE_DIRECTORY "${cuda_compile_output_dir}") + else() + set(generated_file_path "${cuda_compile_output_dir}/${CMAKE_CFG_INTDIR}") + set(generated_file_basename "${cuda_target}_generated_${basename}${generated_extension}") + if(CUDA_SEPARABLE_COMPILATION) + set(format_flag "-dc") + else() + set(format_flag "-c") + endif() + endif() + + # Set all of our file names. Make sure that whatever filenames that have + # generated_file_path in them get passed in through as a command line + # argument, so that the ${CMAKE_CFG_INTDIR} gets expanded at run time + # instead of configure time. + set(generated_file "${generated_file_path}/${generated_file_basename}") + set(cmake_dependency_file "${cuda_compile_intermediate_directory}/${generated_file_basename}.depend") + set(NVCC_generated_dependency_file "${cuda_compile_intermediate_directory}/${generated_file_basename}.NVCC-depend") + set(generated_cubin_file "${generated_file_path}/${generated_file_basename}.cubin.txt") + set(generated_fatbin_file "${generated_file_path}/${generated_file_basename}.fatbin.txt") + set(custom_target_script "${cuda_compile_intermediate_directory}/${generated_file_basename}.cmake") + + # Setup properties for obj files: + if( NOT cuda_compile_to_external_module ) + set_source_files_properties("${generated_file}" + PROPERTIES + EXTERNAL_OBJECT true # This is an object file not to be compiled, but only be linked. + ) + endif() + + # Don't add CMAKE_CURRENT_SOURCE_DIR if the path is already an absolute path. + get_filename_component(file_path "${file}" PATH) + if(IS_ABSOLUTE "${file_path}") + set(source_file "${file}") + else() + set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}") + endif() + + if( NOT cuda_compile_to_external_module AND CUDA_SEPARABLE_COMPILATION) + list(APPEND ${cuda_target}_SEPARABLE_COMPILATION_OBJECTS "${generated_file}") + endif() + + # Convience string for output ########################################### + if(CUDA_BUILD_EMULATION) + set(cuda_build_type "Emulation") + else() + set(cuda_build_type "Device") + endif() + + # Build the NVCC made dependency file ################################### + set(build_cubin OFF) + if ( NOT CUDA_BUILD_EMULATION AND CUDA_BUILD_CUBIN ) + if ( NOT cuda_compile_to_external_module ) + set ( build_cubin ON ) + endif() + endif() + + # Configure the build script + configure_file("${CUDA_run_nvcc}" "${custom_target_script}" @ONLY) + + # So if a user specifies the same cuda file as input more than once, you + # can have bad things happen with dependencies. Here we check an option + # to see if this is the behavior they want. + if(CUDA_ATTACH_VS_BUILD_RULE_TO_CUDA_FILE) + set(main_dep MAIN_DEPENDENCY ${source_file}) + else() + set(main_dep DEPENDS ${source_file}) + endif() + + if(CUDA_VERBOSE_BUILD) + set(verbose_output ON) + elseif(CMAKE_GENERATOR MATCHES "Makefiles") + set(verbose_output "$(VERBOSE)") + else() + set(verbose_output OFF) + endif() + + # Create up the comment string + file(RELATIVE_PATH generated_file_relative_path "${CMAKE_BINARY_DIR}" "${generated_file}") + if(cuda_compile_to_external_module) + set(cuda_build_comment_string "Building NVCC ${cuda_compile_to_external_module_type} file ${generated_file_relative_path}") + else() + set(cuda_build_comment_string "Building NVCC (${cuda_build_type}) object ${generated_file_relative_path}") + endif() + + # Bring in the dependencies. Creates a variable CUDA_NVCC_DEPEND ####### + cuda_include_nvcc_dependencies(${cmake_dependency_file}) + + # Check to see if the build script is newer than the dependency file. If + # it is, regenerate it. + # message("CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE = ${CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE}") + # message("CUDA_NVCC_DEPEND_REGENERATE = ${CUDA_NVCC_DEPEND_REGENERATE}") + # execute_process(COMMAND ls -lTtr "${custom_target_script}" "${cmake_dependency_file}" "${NVCC_generated_dependency_file}") + set(_cuda_generate_dependencies FALSE) + # Note that NVCC_generated_dependency_file is always generated. + if(CUDA_GENERATE_DEPENDENCIES_DURING_CONFIGURE + AND "${custom_target_script}" IS_NEWER_THAN "${NVCC_generated_dependency_file}") + # If the two files were generated about the same time then reversing the + # comparison will also be true, so check the CUDA_NVCC_DEPEND_REGENERATE + # flag. + if ("${NVCC_generated_dependency_file}" IS_NEWER_THAN "${custom_target_script}") + # message("************************************************************************") + # message("Same modification time: ${custom_target_script} ${NVCC_generated_dependency_file}") + if (CUDA_NVCC_DEPEND_REGENERATE OR NOT EXISTS "${NVCC_generated_dependency_file}") + set(_cuda_generate_dependencies TRUE) + endif() + else() + # The timestamp check is valid + set(_cuda_generate_dependencies TRUE) + endif() + endif() + # message("_cuda_generate_dependencies = ${_cuda_generate_dependencies}") + + # If we needed to regenerate the dependency file, do so now. + if (_cuda_generate_dependencies) + set(_cuda_dependency_ccbin) + # message("CUDA_HOST_COMPILER = ${CUDA_HOST_COMPILER}") + if(ccbin_flags MATCHES "\\$\\(VCInstallDir\\)") + set(_cuda_dependency_ccbin_dir) + if (CUDA_VS_DIR AND EXISTS "${CUDA_VS_DIR}/VC/bin") + set(_cuda_dependency_ccbin_dir "${CUDA_VS_DIR}/VC/bin") + elseif( EXISTS "${CMAKE_CXX_COMPILER}" ) + get_filename_component(_cuda_dependency_ccbin_dir "${CMAKE_CXX_COMPILER}" DIRECTORY) + endif() + if( _cuda_dependency_ccbin_dir ) + set(_cuda_dependency_ccbin -D "CCBIN:PATH=${_cuda_dependency_ccbin_dir}") + endif() + elseif(ccbin_flags) + # The CUDA_HOST_COMPILER is set to something interesting, so use the + # ccbin_flags as-is. + set(_cuda_dependency_ccbin ${ccbin_flags}) + endif() + # message("_cuda_dependency_ccbin = ${_cuda_dependency_ccbin}") + if(_cuda_dependency_ccbin OR NOT ccbin_flags) + # Only do this if we have some kind of host compiler defined in + # _cuda_dependency_ccbin or ccbin_flags isn't set. + + set( _execute_process_args + COMMAND ${CMAKE_COMMAND} + -D generate_dependency_only:BOOL=TRUE + -D verbose:BOOL=TRUE + ${_cuda_dependency_ccbin} + -D "generated_file:STRING=${generated_file}" + -D "generated_cubin_file:STRING=${generated_cubin_file}" + -P "${custom_target_script}" + WORKING_DIRECTORY "${cuda_compile_intermediate_directory}" + RESULT_VARIABLE _cuda_dependency_error + OUTPUT_VARIABLE _cuda_dependency_output + ERROR_VARIABLE _cuda_dependency_output + ) + if( CUDA_BATCH_DEPENDS_LOG ) + file( APPEND ${CUDA_BATCH_DEPENDS_LOG} "COMMENT;Generating dependencies for ${file};${_execute_process_args}\n" ) + else() + message(STATUS "Generating dependencies for ${file}") + execute_process( + ${_execute_process_args} + ) + endif() + if (_cuda_dependency_error) + message(WARNING "Error (${_cuda_dependency_error}) generating dependencies for ${file}:\n\n${_cuda_dependency_output}. This will be postponed until build time.") + else() + # Try and reload the dependies + cuda_include_nvcc_dependencies(${cmake_dependency_file}) + endif() + endif() + endif() + + # Build the generated file and dependency file ########################## + set( _custom_command_args + OUTPUT ${generated_file} + # These output files depend on the source_file and the contents of cmake_dependency_file + ${main_dep} + DEPENDS ${CUDA_NVCC_DEPEND} + DEPENDS ${custom_target_script} + # Make sure the output directory exists before trying to write to it. + COMMAND ${CMAKE_COMMAND} -E make_directory "${generated_file_path}" + COMMAND ${CMAKE_COMMAND} + -D verbose:BOOL=${verbose_output} + -D check_dependencies:BOOL=${CUDA_CHECK_DEPENDENCIES_DURING_COMPILE} + ${ccbin_flags} + -D build_configuration:STRING=${CUDA_build_configuration} + -D "generated_file:STRING=${generated_file}" + -D "generated_cubin_file:STRING=${generated_cubin_file}" + -D "generated_fatbin_file:STRING=${generated_fatbin_file}" + -P "${custom_target_script}" + WORKING_DIRECTORY "${cuda_compile_intermediate_directory}" + COMMENT "${cuda_build_comment_string}" + ) + if( CUDA_BATCH_BUILD_LOG ) + list(APPEND CUDA_BATCH_BUILD_OUTPUTS ${generated_file}) + set_property( GLOBAL APPEND PROPERTY CUDA_BATCH_BUILD_DEPENDS ${source_file} ${CUDA_NVCC_DEPEND} ${custom_target_script}) + file( APPEND ${CUDA_BATCH_BUILD_LOG} "${_custom_command_args}\n" ) + endif() + add_custom_command( ${_custom_command_args} ) + + # Make sure the build system knows the file is generated. + set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE) + + list(APPEND _cuda_wrap_generated_files ${generated_file}) + + # Add the other files that we want cmake to clean on a cleanup ########## + list(APPEND CUDA_ADDITIONAL_CLEAN_FILES "${cmake_dependency_file}") + list(REMOVE_DUPLICATES CUDA_ADDITIONAL_CLEAN_FILES) + set(CUDA_ADDITIONAL_CLEAN_FILES ${CUDA_ADDITIONAL_CLEAN_FILES} CACHE INTERNAL "List of intermediate files that are part of the cuda dependency scanning.") + + endif() + endforeach() + + # Set the return parameter + set(${generated_files} ${_cuda_wrap_generated_files}) +endmacro() + +function(_cuda_get_important_host_flags important_flags flag_string) + if(CMAKE_GENERATOR MATCHES "Visual Studio") + string(REGEX MATCHALL "/M[DT][d]?" flags "${flag_string}") + list(APPEND ${important_flags} ${flags}) + else() + string(REGEX MATCHALL "-fPIC" flags "${flag_string}") + list(APPEND ${important_flags} ${flags}) + endif() + set(${important_flags} ${${important_flags}} PARENT_SCOPE) +endfunction() + +############################################################################### +############################################################################### +# Separable Compilation Link +############################################################################### +############################################################################### + +# Compute the filename to be used by CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS +function(CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME output_file_var cuda_target object_files) + if (object_files) + set(generated_extension ${CMAKE_${CUDA_C_OR_CXX}_OUTPUT_EXTENSION}) + set(output_file "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${cuda_target}.dir/${CMAKE_CFG_INTDIR}/${cuda_target}_intermediate_link${generated_extension}") + else() + set(output_file) + endif() + + set(${output_file_var} "${output_file}" PARENT_SCOPE) +endfunction() + +# Setup the build rule for the separable compilation intermediate link file. +function(CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS output_file cuda_target options object_files) + if (object_files) + + set_source_files_properties("${output_file}" + PROPERTIES + EXTERNAL_OBJECT TRUE # This is an object file not to be compiled, but only + # be linked. + GENERATED TRUE # This file is generated during the build + ) + + # For now we are ignoring all the configuration specific flags. + set(nvcc_flags) + CUDA_PARSE_NVCC_OPTIONS(nvcc_flags ${options}) + if(CUDA_64_BIT_DEVICE_CODE) + list(APPEND nvcc_flags -m64) + else() + list(APPEND nvcc_flags -m32) + endif() + # If -ccbin, --compiler-bindir has been specified, don't do anything. Otherwise add it here. + list( FIND nvcc_flags "-ccbin" ccbin_found0 ) + list( FIND nvcc_flags "--compiler-bindir" ccbin_found1 ) + if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 AND CUDA_HOST_COMPILER ) + # Match VERBATIM check below. + if(CUDA_HOST_COMPILER MATCHES "\\$\\(VCInstallDir\\)") + list(APPEND nvcc_flags -ccbin "\"${CUDA_HOST_COMPILER}\"") + else() + list(APPEND nvcc_flags -ccbin "${CUDA_HOST_COMPILER}") + endif() + endif() + + # Create a list of flags specified by CUDA_NVCC_FLAGS_${CONFIG} and CMAKE_${CUDA_C_OR_CXX}_FLAGS* + set(config_specific_flags) + set(flags) + foreach(config ${CUDA_configuration_types}) + string(TOUPPER ${config} config_upper) + # Add config specific flags + foreach(f ${CUDA_NVCC_FLAGS_${config_upper}}) + list(APPEND config_specific_flags $<$:${f}>) + endforeach() + set(important_host_flags) + _cuda_get_important_host_flags(important_host_flags "${CMAKE_${CUDA_C_OR_CXX}_FLAGS_${config_upper}}") + foreach(f ${important_host_flags}) + list(APPEND flags $<$:-Xcompiler> $<$:${f}>) + endforeach() + endforeach() + # Add CMAKE_${CUDA_C_OR_CXX}_FLAGS + set(important_host_flags) + _cuda_get_important_host_flags(important_host_flags "${CMAKE_${CUDA_C_OR_CXX}_FLAGS}") + foreach(f ${important_host_flags}) + list(APPEND flags -Xcompiler ${f}) + endforeach() + + # Add our general CUDA_NVCC_FLAGS with the configuration specifig flags + set(nvcc_flags ${CUDA_NVCC_FLAGS} ${config_specific_flags} ${nvcc_flags}) + + file(RELATIVE_PATH output_file_relative_path "${CMAKE_BINARY_DIR}" "${output_file}") + + # Some generators don't handle the multiple levels of custom command + # dependencies correctly (obj1 depends on file1, obj2 depends on obj1), so + # we work around that issue by compiling the intermediate link object as a + # pre-link custom command in that situation. + set(do_obj_build_rule TRUE) + if (MSVC_VERSION GREATER 1599 AND MSVC_VERSION LESS 1800) + # VS 2010 and 2012 have this problem. + set(do_obj_build_rule FALSE) + endif() + + set(_verbatim VERBATIM) + if(nvcc_flags MATCHES "\\$\\(VCInstallDir\\)") + set(_verbatim "") + endif() + + if (do_obj_build_rule) + add_custom_command( + OUTPUT ${output_file} + DEPENDS ${object_files} + COMMAND ${CUDA_NVCC_EXECUTABLE} ${nvcc_flags} -dlink ${object_files} -o ${output_file} + ${flags} + COMMENT "Building NVCC intermediate link file ${output_file_relative_path}" + ${_verbatim} + ) + else() + get_filename_component(output_file_dir "${output_file}" DIRECTORY) + add_custom_command( + TARGET ${cuda_target} + PRE_LINK + COMMAND ${CMAKE_COMMAND} -E echo "Building NVCC intermediate link file ${output_file_relative_path}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${output_file_dir}" + COMMAND ${CUDA_NVCC_EXECUTABLE} ${nvcc_flags} ${flags} -dlink ${object_files} -o "${output_file}" + ${_verbatim} + ) + endif() + endif() +endfunction() + +############################################################################### +############################################################################### +# ADD LIBRARY +############################################################################### +############################################################################### +macro(CUDA_ADD_LIBRARY cuda_target) + + CUDA_ADD_CUDA_INCLUDE_ONCE() + + # Separate the sources from the options + CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + CUDA_BUILD_SHARED_LIBRARY(_cuda_shared_flag ${ARGN}) + # Create custom commands and targets for each file. + CUDA_WRAP_SRCS( ${cuda_target} OBJ _generated_files ${_sources} + ${_cmake_options} ${_cuda_shared_flag} + OPTIONS ${_options} ) + + # Compute the file name of the intermedate link file used for separable + # compilation. + CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${cuda_target} "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}") + + # Add the library. + add_library(${cuda_target} ${_cmake_options} + ${_generated_files} + ${_sources} + ${link_file} + ) + + # Add a link phase for the separable compilation if it has been enabled. If + # it has been enabled then the ${cuda_target}_SEPARABLE_COMPILATION_OBJECTS + # variable will have been defined. + CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS("${link_file}" ${cuda_target} "${_options}" "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}") + + target_link_libraries(${cuda_target} + ${CUDA_LIBRARIES} + ) + + if(CUDA_SEPARABLE_COMPILATION) + target_link_libraries(${cuda_target} + ${CUDA_cudadevrt_LIBRARY} + ) + endif() + + # We need to set the linker language based on what the expected generated file + # would be. CUDA_C_OR_CXX is computed based on CUDA_HOST_COMPILATION_CPP. + set_target_properties(${cuda_target} + PROPERTIES + LINKER_LANGUAGE ${CUDA_C_OR_CXX} + ) + +endmacro() + + +############################################################################### +############################################################################### +# ADD EXECUTABLE +############################################################################### +############################################################################### +macro(CUDA_ADD_EXECUTABLE cuda_target) + + CUDA_ADD_CUDA_INCLUDE_ONCE() + + # Separate the sources from the options + CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + # Create custom commands and targets for each file. + CUDA_WRAP_SRCS( ${cuda_target} OBJ _generated_files ${_sources} OPTIONS ${_options} ) + + # Compute the file name of the intermedate link file used for separable + # compilation. + CUDA_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${cuda_target} "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}") + + # Add the library. + add_executable(${cuda_target} ${_cmake_options} + ${_generated_files} + ${_sources} + ${link_file} + ) + + # Add a link phase for the separable compilation if it has been enabled. If + # it has been enabled then the ${cuda_target}_SEPARABLE_COMPILATION_OBJECTS + # variable will have been defined. + CUDA_LINK_SEPARABLE_COMPILATION_OBJECTS("${link_file}" ${cuda_target} "${_options}" "${${cuda_target}_SEPARABLE_COMPILATION_OBJECTS}") + + target_link_libraries(${cuda_target} + ${CUDA_LIBRARIES} + ) + + # We need to set the linker language based on what the expected generated file + # would be. CUDA_C_OR_CXX is computed based on CUDA_HOST_COMPILATION_CPP. + set_target_properties(${cuda_target} + PROPERTIES + LINKER_LANGUAGE ${CUDA_C_OR_CXX} + ) + +endmacro() + + +############################################################################### +############################################################################### +# (Internal) helper for manually added cuda source files with specific targets +############################################################################### +############################################################################### +macro(cuda_compile_base cuda_target format generated_files) + # Separate the sources from the options + CUDA_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN}) + + # Create custom commands and targets for each file. + CUDA_WRAP_SRCS( ${cuda_target} ${format} _generated_files ${_sources} + ${_cmake_options} OPTIONS ${_options}) + + set( ${generated_files} ${_generated_files}) + +endmacro() + +############################################################################### +############################################################################### +# CUDA COMPILE +############################################################################### +############################################################################### +macro(CUDA_COMPILE generated_files) + cuda_compile_base(cuda_compile OBJ ${generated_files} ${ARGN}) +endmacro() + +############################################################################### +############################################################################### +# CUDA COMPILE PTX +############################################################################### +############################################################################### +macro(CUDA_COMPILE_PTX generated_files) + cuda_compile_base(cuda_compile_ptx PTX ${generated_files} ${ARGN}) +endmacro() + +############################################################################### +############################################################################### +# CUDA COMPILE FATBIN +############################################################################### +############################################################################### +macro(CUDA_COMPILE_FATBIN generated_files) + cuda_compile_base(cuda_compile_fatbin FATBIN ${generated_files} ${ARGN}) +endmacro() + +############################################################################### +############################################################################### +# CUDA COMPILE CUBIN +############################################################################### +############################################################################### +macro(CUDA_COMPILE_CUBIN generated_files) + cuda_compile_base(cuda_compile_cubin CUBIN ${generated_files} ${ARGN}) +endmacro() + + +############################################################################### +############################################################################### +# CUDA ADD CUFFT TO TARGET +############################################################################### +############################################################################### +macro(CUDA_ADD_CUFFT_TO_TARGET target) + if (CUDA_BUILD_EMULATION) + target_link_libraries(${target} ${CUDA_cufftemu_LIBRARY}) + else() + target_link_libraries(${target} ${CUDA_cufft_LIBRARY}) + endif() +endmacro() + +############################################################################### +############################################################################### +# CUDA ADD CUBLAS TO TARGET +############################################################################### +############################################################################### +macro(CUDA_ADD_CUBLAS_TO_TARGET target) + if (CUDA_BUILD_EMULATION) + target_link_libraries(${target} ${CUDA_cublasemu_LIBRARY}) + else() + target_link_libraries(${target} ${CUDA_cublas_LIBRARY} ${CUDA_cublas_device_LIBRARY}) + endif() +endmacro() + +############################################################################### +############################################################################### +# CUDA BUILD CLEAN TARGET +############################################################################### +############################################################################### +macro(CUDA_BUILD_CLEAN_TARGET) + # Call this after you add all your CUDA targets, and you will get a convience + # target. You should also make clean after running this target to get the + # build system to generate all the code again. + + set(cuda_clean_target_name clean_cuda_depends) + if (CMAKE_GENERATOR MATCHES "Visual Studio") + string(TOUPPER ${cuda_clean_target_name} cuda_clean_target_name) + endif() + add_custom_target(${cuda_clean_target_name} + COMMAND ${CMAKE_COMMAND} -E remove ${CUDA_ADDITIONAL_CLEAN_FILES}) + + # Clear out the variable, so the next time we configure it will be empty. + # This is useful so that the files won't persist in the list after targets + # have been removed. + set(CUDA_ADDITIONAL_CLEAN_FILES "" CACHE INTERNAL "List of intermediate files that are part of the cuda dependency scanning.") +endmacro() + + +############################################################################## +############################################################################### +# CUDA BATCH BUILD BEGIN +############################################################################### +############################################################################### +function(CUDA_BATCH_BUILD_BEGIN target) + if(MSVC AND CUDA_ENABLE_BATCHING) + set( CUDA_BATCH_BUILD_LOG "${CMAKE_BINARY_DIR}/CMakeFiles/${target}.dir/cudaBatchBuild.log" ) + file( REMOVE ${CUDA_BATCH_BUILD_LOG} ) + set( CUDA_BATCH_BUILD_LOG "${CUDA_BATCH_BUILD_LOG}" PARENT_SCOPE ) # export variable + set_property( GLOBAL PROPERTY CUDA_BATCH_BUILD_DEPENDS "" ) + endif() +endfunction() + + +############################################################################### +############################################################################### +# CUDA BATCH BUILD END +############################################################################### +############################################################################### +function(CUDA_BATCH_BUILD_END target) + set(BATCH_CMAKE_SCRIPT "${CMAKE_SOURCE_DIR}/CMake/cuda/FindCUDA/batchCMake.py") + find_package(PythonInterp) + + if( CUDA_BATCH_BUILD_LOG ) + set(cuda_batch_build_target "_${target}_cudaBatchBuild") + set(stamp_dir "${CMAKE_BINARY_DIR}/CMakeFiles/${target}.dir/${CMAKE_CFG_INTDIR}") + set(stamp_file ${stamp_dir}/cuda-batch-build.stamp) + get_property(cuda_depends GLOBAL PROPERTY CUDA_BATCH_BUILD_DEPENDS) + list(REMOVE_DUPLICATES cuda_depends) + add_custom_target( ${cuda_batch_build_target} + COMMENT "CUDA batch build ${cuda_batch_build_target}..." + COMMAND "${PYTHON_EXECUTABLE}" "${BATCH_CMAKE_SCRIPT}" -t ${cuda_batch_build_target} -c ${CUDA_BATCH_BUILD_LOG} -s "\"%24(VCInstallDir)=$(VCInstallDir)\\\"" -s "%24(ConfigurationName)=$(ConfigurationName)" -s "%24(Configuration)=$(Configuration)" -s "%24(VCToolsVersion)=$(VCToolsVersion)" -s "%24(Platform)=$(Platform)" -s "%24(PlatformTarget)=$(PlatformTarget)" # %24 is the '$' character - needed to escape '$' in VS rule + DEPENDS ${cuda_depends} + ) + add_dependencies( ${target} ${cuda_batch_build_target} ) + endif() + + set( CUDA_BATCH_BUILD_LOG ) + set_property( GLOBAL PROPERTY CUDA_BATCH_BUILD_DEPENDS "" ) +endfunction() + +############################################################################## +############################################################################### +# CUDA BATCH DEPENDS BEGIN +############################################################################### +############################################################################### +function(CUDA_BATCH_DEPENDS_BEGIN) + if(MSVC AND CUDA_ENABLE_BATCHING) + set( CUDA_BATCH_DEPENDS_LOG "${CMAKE_BINARY_DIR}/CMakeFiles/cudaBatchDepends.log" ) + file( REMOVE ${CUDA_BATCH_DEPENDS_LOG} ) + set( CUDA_BATCH_DEPENDS_LOG "${CUDA_BATCH_DEPENDS_LOG}" PARENT_SCOPE ) # export variable + + set(BATCH_CMAKE_SCRIPT "${CMAKE_SOURCE_DIR}/CMake/cuda/FindCUDA/batchCMake.py") + # Create batch file to setup VS environment, since CUDA 8 broke running nvcc outside + # of VS environment. You could get around this with the following command with newer + # versions of cmake (3.5.2 worked for me, but 3.2.1 didn't like the && ): + # execute_process( COMMAND ${CUDA_VC_VARS_ALL_BAT} && ${PYTHON_EXECUTABLE} ... ) + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(BUILD_BITS amd64) + else() + set(BUILD_BITS x86) + endif() + file(WRITE ${CUDA_BATCH_DEPENDS_LOG}.vsconfigure.bat + "@echo OFF\n" + "REM Created by FindCUDA.cmake\n" + "@call \"${CUDA_VC_VARS_ALL_BAT}\" ${BUILD_BITS}\n" + "\"${PYTHON_EXECUTABLE}\" \"${BATCH_CMAKE_SCRIPT}\" -e \"${CUDA_BATCH_DEPENDS_LOG}\" -t \"CUDA batch dependencies\"" + ) + endif() +endfunction() + +############################################################################### +############################################################################### +# CUDA BATCH DEPENDS END +############################################################################### +############################################################################### +function(CUDA_BATCH_DEPENDS_END) + if( CUDA_BATCH_DEPENDS_LOG ) + if( EXISTS ${CUDA_BATCH_DEPENDS_LOG} ) + message(STATUS "CUDA batch dependencies ...") + execute_process( + COMMAND ${CUDA_BATCH_DEPENDS_LOG}.vsconfigure.bat + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE _cuda_batch_depends_output + ERROR_VARIABLE _cuda_batch_depends_output + RESULT_VARIABLE _cuda_batch_depends_result + ) + message(STATUS ${_cuda_batch_depends_output}) + if( ${_cuda_batch_depends_result} ) + message(FATAL_ERROR "Failed") + else() + message(SEND_ERROR "Please reconfigure to ensure that dependencies are incorporated into the build files") + endif() + endif() + endif() + + set( CUDA_BATCH_DEPENDS_LOG ) + +endfunction() diff --git a/Extra-Methods-Patches/tetra-nerf/cmake/FindOptiX.cmake b/Extra-Methods-Patches/tetra-nerf/cmake/FindOptiX.cmake new file mode 100644 index 0000000000..502a4f8eed --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/cmake/FindOptiX.cmake @@ -0,0 +1,115 @@ +# - Find OptiX +# +# This module defines: +# OptiX_FOUND +# OptiX_INCLUDE +# OPTIX_INCLUDE_DIR +# OPTIX_ROOT_DIR +# OPTIX_INSTALL_DIR +# +# Accepted inputs, in priority order: +# -DOPTIX_INCLUDE_DIR=... +# -DOPTIX_INSTALL_DIR=... +# -DOPTIX_ROOT_DIR=... +# ENV{OPTIX_INCLUDE_DIR} +# ENV{OPTIX_INSTALL_DIR} +# ENV{OPTIX_ROOT_DIR} +# ENV{OPTIX_PATH} +# +# The output variable used by this project is: +# OptiX_INCLUDE + +include(FindPackageHandleStandardArgs) + +function(OptiX_report_error msg) + message(FATAL_ERROR "${msg}") +endfunction() + +# Normalize incoming cache/env values +if(NOT OPTIX_INCLUDE_DIR AND DEFINED ENV{OPTIX_INCLUDE_DIR}) + set(OPTIX_INCLUDE_DIR "$ENV{OPTIX_INCLUDE_DIR}" CACHE PATH "OptiX include directory" FORCE) +endif() + +if(NOT OPTIX_INSTALL_DIR AND DEFINED ENV{OPTIX_INSTALL_DIR}) + set(OPTIX_INSTALL_DIR "$ENV{OPTIX_INSTALL_DIR}" CACHE PATH "OptiX install directory" FORCE) +endif() + +if(NOT OPTIX_ROOT_DIR AND DEFINED ENV{OPTIX_ROOT_DIR}) + set(OPTIX_ROOT_DIR "$ENV{OPTIX_ROOT_DIR}" CACHE PATH "OptiX root directory" FORCE) +endif() + +if(NOT OPTIX_INSTALL_DIR AND DEFINED ENV{OPTIX_PATH}) + set(OPTIX_INSTALL_DIR "$ENV{OPTIX_PATH}" CACHE PATH "OptiX install directory" FORCE) +endif() + +# Candidate roots +set(_optix_roots "") +if(OPTIX_INCLUDE_DIR) + list(APPEND _optix_roots "${OPTIX_INCLUDE_DIR}") +endif() +if(OPTIX_INSTALL_DIR) + list(APPEND _optix_roots "${OPTIX_INSTALL_DIR}" "${OPTIX_INSTALL_DIR}/include") +endif() +if(OPTIX_ROOT_DIR) + list(APPEND _optix_roots "${OPTIX_ROOT_DIR}" "${OPTIX_ROOT_DIR}/include") +endif() + +if(WIN32) + list(APPEND _optix_roots + "$ENV{ProgramFiles}/NVIDIA Corporation/OptiX SDK 9.1.0" + "$ENV{ProgramFiles}/NVIDIA Corporation/OptiX SDK 9.0.0" + "$ENV{ProgramFiles}/NVIDIA Corporation/OptiX SDK 8.1.0" + "$ENV{ProgramFiles}/NVIDIA Corporation/OptiX SDK 8.0.0" + "$ENV{ProgramFiles}/NVIDIA Corporation/OptiX SDK 9.1.0/include" + "$ENV{ProgramFiles}/NVIDIA Corporation/OptiX SDK 9.0.0/include" + "$ENV{ProgramFiles}/NVIDIA Corporation/OptiX SDK 8.1.0/include" + "$ENV{ProgramFiles}/NVIDIA Corporation/OptiX SDK 8.0.0/include" + ) +else() + list(APPEND _optix_roots + "/opt/optix" + "/opt/optix/include" + "/usr/local/optix" + "/usr/local/optix/include" + ) +endif() + +find_path( + OPTIX_INCLUDE_DIR + NAMES optix.h + HINTS ${_optix_roots} + PATH_SUFFIXES include +) + +if(NOT OPTIX_INCLUDE_DIR) + OptiX_report_error("OptiX headers (optix.h and friends) not found. Please locate before proceeding.") +endif() + +# Canonical project-facing variable +set(OptiX_INCLUDE "${OPTIX_INCLUDE_DIR}") + +# Backfill root/install if missing +if(NOT OPTIX_INSTALL_DIR) + get_filename_component(_optix_parent "${OPTIX_INCLUDE_DIR}" DIRECTORY) + if(EXISTS "${_optix_parent}/optix.h") + set(OPTIX_INSTALL_DIR "${_optix_parent}" CACHE PATH "OptiX install directory" FORCE) + else() + get_filename_component(_optix_root "${OPTIX_INCLUDE_DIR}" DIRECTORY) + set(OPTIX_INSTALL_DIR "${_optix_root}" CACHE PATH "OptiX install directory" FORCE) + endif() +endif() + +if(NOT OPTIX_ROOT_DIR) + set(OPTIX_ROOT_DIR "${OPTIX_INSTALL_DIR}" CACHE PATH "OptiX root directory" FORCE) +endif() + +find_package_handle_standard_args( + OptiX + REQUIRED_VARS OPTIX_INCLUDE_DIR +) + +mark_as_advanced( + OPTIX_INCLUDE_DIR + OPTIX_INSTALL_DIR + OPTIX_ROOT_DIR +) \ No newline at end of file diff --git a/Extra-Methods-Patches/tetra-nerf/cmake/FindTorch.cmake b/Extra-Methods-Patches/tetra-nerf/cmake/FindTorch.cmake new file mode 100644 index 0000000000..15d2d0a958 --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/cmake/FindTorch.cmake @@ -0,0 +1,79 @@ +if(NOT DEFINED PYTHON_EXECUTABLE) + execute_process(COMMAND python -c "import sys; print(sys.executable,end='')" OUTPUT_VARIABLE PYTHON_EXECUTABLE) + execute_process(COMMAND "${PYTHON_EXECUTABLE}" --version OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE TORCH_PYTHON_VERSION) + message(STATUS "Using ${TORCH_PYTHON_VERSION}") + execute_process(COMMAND "${PYTHON_EXECUTABLE}" -c "import torch; print(f'{torch.__version__}',end='')" RESULT_VARIABLE STATUS OUTPUT_VARIABLE TORCH_VERSION) + if(STATUS AND NOT STATUS EQUAL 0) + message(FATAL_ERROR "Could not find torch library using python path: ${PYTHON_EXECUTABLE}") + endif() + message(STATUS "Found torch ${TORCH_VERSION}") +endif() + +if(NOT DEFINED CUDA_TOOLKIT_ROOT_DIR) + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" -c "import torch.utils.cpp_extension; print(f'{torch.utils.cpp_extension.CUDA_HOME}',end='')" + RESULT_VARIABLE STATUS + OUTPUT_VARIABLE CUDA_TOOLKIT_ROOT_DIR + ) +endif() + +if(NOT DEFINED TORCH_LIBRARY_DIRS) + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" -c "import torch.utils.cpp_extension; print(';'.join(torch.utils.cpp_extension.library_paths(False)),end='')" + COMMAND_ERROR_IS_FATAL ANY + OUTPUT_VARIABLE TORCH_LIBRARY_DIRS + ) +endif() + +if(NOT DEFINED TORCH_INCLUDE_DIRS) + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" -c "import torch.utils.cpp_extension; print(';'.join(torch.utils.cpp_extension.include_paths(False)),end='')" + COMMAND_ERROR_IS_FATAL ANY + OUTPUT_VARIABLE TORCH_INCLUDE_DIRS + ) +endif() + +if("$ENV{CUDAARCHS}" STREQUAL "") + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" -c "import torch.utils.cpp_extension; print(' '.join(sorted(set(x.split('_')[-1] for x in torch.utils.cpp_extension._get_cuda_arch_flags()))), end='')" + COMMAND_ERROR_IS_FATAL ANY + OUTPUT_VARIABLE CMAKE_CUDA_ARCHITECTURES + ) +endif() + +message(STATUS "Using torch libraries: ${TORCH_LIBRARY_DIRS}") +message(STATUS "Using torch includes: ${TORCH_INCLUDE_DIRS}") +message(STATUS "Using CUDA toolkit: ${CUDA_TOOLKIT_ROOT_DIR}") +message(STATUS "Using CUDA architectures: ${CMAKE_CUDA_ARCHITECTURES}") + +include_directories(${TORCH_INCLUDE_DIRS}) +link_directories(${TORCH_LIBRARY_DIRS}) + +set(TORCH_LIBRARIES c10 torch torch_cpu torch_python) + +if(WIN32) + # CUDA flags only. Keep host flags inside -Xcompiler. + string(APPEND CMAKE_CUDA_FLAGS + " -D__CUDA_NO_HALF_OPERATORS__" + " -D__CUDA_NO_HALF_CONVERSIONS__" + " -D__CUDA_NO_HALF2_OPERATORS__" + " --expt-relaxed-constexpr" + " -O3" + " --use_fast_math" + " -Xcompiler=/bigobj" + ) + + # Only real MSVC host flags here. + string(APPEND CMAKE_CXX_FLAGS " /EHsc") +else() + string(APPEND CMAKE_CUDA_FLAGS + " -D__CUDA_NO_HALF_OPERATORS__" + " -D__CUDA_NO_HALF_CONVERSIONS__" + " -D__CUDA_NO_HALF2_OPERATORS__" + " --expt-relaxed-constexpr" + " --compiler-options '-fPIC'" + " -O3" + " --use_fast_math" + ) + string(APPEND CMAKE_CXX_FLAGS " -Wno-deprecated-declarations -D_GLIBCXX_USE_CXX11_ABI=0") +endif() \ No newline at end of file diff --git a/Extra-Methods-Patches/tetra-nerf/setup.py b/Extra-Methods-Patches/tetra-nerf/setup.py new file mode 100644 index 0000000000..2be1f960bc --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/setup.py @@ -0,0 +1,519 @@ +from __future__ import annotations + +import os +import shutil +import subprocess +import sys +from pathlib import Path + +from setuptools import Extension, setup, find_packages +from setuptools.command.build_ext import build_ext + + +ROOT = Path(__file__).resolve().parent +PKG_NAME = "tetra-nerf" +VERSION = "0.1.1" + +VANILLA_CUDA_VERSION = "11.8" +VANILLA_MSVC_TOOLSET = "14.38.33130" +VANILLA_MSVC_MAJOR = "v143" + + +def _norm(p: str | Path | None) -> str: + if not p: + return "" + return os.path.normpath(str(p)) + + +def _cmake_path(p: str | Path | None) -> str: + return _norm(p).replace("\\", "/") + + +def _existing_dir(*candidates: str | Path | None) -> str: + for c in candidates: + if not c: + continue + p = Path(str(c)) + if p.exists() and p.is_dir(): + return _norm(p) + return "" + + +def _existing_file(*candidates: str | Path | None) -> str: + for c in candidates: + if not c: + continue + p = Path(str(c)) + if p.exists() and p.is_file(): + return _norm(p) + return "" + + +def _safe_env_bool(name: str, default: bool = False) -> bool: + v = os.environ.get(name, "").strip().lower() + if not v: + return default + return v in {"1", "true", "yes", "on"} + + +def _print_info(label: str, value: object) -> None: + print(f"[INFO] {label} = {value}") + + +def _dedupe_paths(parts: list[str]) -> list[str]: + out: list[str] = [] + seen: set[str] = set() + for p in parts: + if not p: + continue + pn = _norm(p) + key = pn.lower() + if key in seen: + continue + seen.add(key) + out.append(pn) + return out + + +def _remove_env_keys_casefold(env: dict[str, str], *keys: str) -> None: + wanted = {k.casefold() for k in keys} + to_del = [k for k in list(env.keys()) if k.casefold() in wanted] + for k in to_del: + env.pop(k, None) + + +def _clean_cuda_path_entries(old_parts: list[str], selected_cuda_root: str, cuda_mode: str) -> list[str]: + selected_cuda_root_norm = _norm(selected_cuda_root).lower() + out: list[str] = [] + + for p in old_parts: + pn = _norm(p) + if not pn: + continue + low = pn.lower() + + # in vanilla, keep only the selected CUDA tree + if "nvidia gpu computing toolkit" in low and "\\cuda\\" in low: + if cuda_mode == "vanilla": + if not low.startswith(selected_cuda_root_norm): + continue + + # purge ROCm/HIP noise that breaks torch cpp_extension on Windows + if any(token in low for token in [ + "\\rocm\\", + "\\hip\\", + "amd\\rocm", + "rocm\\bin", + "hip\\bin", + ]): + continue + + out.append(pn) + + return _dedupe_paths(out) + + +def _discover_cuda_mode() -> str: + mode = os.environ.get("NS_CUDA_MODE", "").strip().lower() + if mode in {"vanilla", "experimental-env"}: + return mode + return "vanilla" + + +def _vanilla_cuda_root_candidate() -> Path: + return Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA GPU Computing Toolkit" / "CUDA" / f"v{VANILLA_CUDA_VERSION}" + + +def _discover_cuda_root(cuda_mode: str) -> str: + vanilla_candidates = [ + _vanilla_cuda_root_candidate(), + os.environ.get("CUDAToolkit_ROOT"), + os.environ.get("CUDA_HOME"), + os.environ.get("CUDA_PATH"), + ] + + experimental_candidates = [ + os.environ.get("CUDAToolkit_ROOT"), + os.environ.get("CUDA_HOME"), + os.environ.get("CUDA_PATH"), + _vanilla_cuda_root_candidate(), + ] + + candidates = vanilla_candidates if cuda_mode == "vanilla" else experimental_candidates + cuda_root = _existing_dir(*candidates) + if not cuda_root: + raise RuntimeError("CUDA toolkit root not found.") + return cuda_root + + +def _discover_nvcc(cuda_root: str, cuda_mode: str) -> str: + root_nvcc = Path(cuda_root) / "bin" / "nvcc.exe" + if root_nvcc.exists(): + return _norm(root_nvcc) + + if cuda_mode == "experimental-env": + nvcc = shutil.which("nvcc.exe") or shutil.which("nvcc") + if nvcc: + return _norm(nvcc) + + raise RuntimeError("nvcc not found under selected CUDA toolkit.") + + +def _discover_optix_root() -> str: + candidates = [ + os.environ.get("OPTIX_ROOT_DIR"), + os.environ.get("OPTIX_INSTALL_DIR"), + os.environ.get("OPTIX_PATH"), + os.environ.get("OPTIX_HOME"), + Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA Corporation" / "OptiX SDK 9.1.0", + Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA Corporation" / "OptiX SDK 9.0.0", + Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA Corporation" / "OptiX SDK 8.1.0", + Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA Corporation" / "OptiX SDK 8.0.0", + ] + return _existing_dir(*candidates) + + +def _discover_optix_include(optix_root: str) -> str: + candidates = [ + os.environ.get("OPTIX_INCLUDE_DIR"), + ] + if optix_root: + candidates.insert(0, str(Path(optix_root) / "include")) + candidates.insert(1, optix_root) + + include_dir = _existing_dir(*candidates) + if include_dir and (Path(include_dir) / "optix.h").exists(): + return include_dir + return "" + + +def _torch_cmake_prefixes() -> list[str]: + prefixes: list[str] = [] + + conda_prefix = os.environ.get("CONDA_PREFIX", "") + if conda_prefix: + prefixes.append(_norm(Path(conda_prefix))) + prefixes.append(_norm(Path(conda_prefix) / "Library")) + prefixes.append(_norm(Path(conda_prefix) / "Lib")) + prefixes.append(_norm(Path(conda_prefix) / "lib" / "site-packages")) + + try: + import torch # type: ignore + + torch_dir = Path(torch.__file__).resolve().parent + prefixes.append(_norm(torch_dir)) + prefixes.append(_norm(torch_dir.parent)) + except Exception: + pass + + return _dedupe_paths(prefixes) + + +def _discover_generator() -> str: + return os.environ.get("CMAKE_GENERATOR", "Visual Studio 17 2022").strip() or "Visual Studio 17 2022" + + +def _discover_toolset() -> str: + explicit = os.environ.get("CMAKE_GENERATOR_TOOLSET", "").strip() + if explicit: + return explicit + return "" + + +def _default_vanilla_toolset(cuda_root: str) -> str: + return f"{VANILLA_MSVC_MAJOR},version={VANILLA_MSVC_TOOLSET},cuda={cuda_root}" + + +def _detect_build_type() -> str: + return "Debug" if os.environ.get("DEBUG", "0") == "1" else "Release" + + +def _find_cl_from_env() -> str: + vctools = _norm(os.environ.get("VCToolsInstallDir")) + if vctools: + candidate = Path(vctools) / "bin" / "Hostx64" / "x64" / "cl.exe" + if candidate.exists(): + return _norm(candidate) + + candidates = [ + os.environ.get("CMAKE_CXX_COMPILER"), + os.environ.get("CXX"), + os.environ.get("CC"), + shutil.which("cl.exe"), + ] + return _existing_file(*candidates) + + +def _read_vcvars_paths() -> tuple[str, str]: + vctools = _norm(os.environ.get("VCToolsInstallDir")) + vcinst = _norm(os.environ.get("VCINSTALLDIR")) + return vctools, vcinst + + +def _ensure_clean_toolset_cache(build_temp: Path, desired_toolset: str) -> None: + cache_file = build_temp / "CMakeCache.txt" + if not cache_file.exists(): + return + + try: + text = cache_file.read_text(encoding="utf-8", errors="ignore") + except Exception: + text = "" + + old_toolset = "" + for line in text.splitlines(): + if line.startswith("CMAKE_GENERATOR_TOOLSET:INTERNAL=") or line.startswith("CMAKE_GENERATOR_TOOLSET:STRING="): + old_toolset = line.split("=", 1)[1].strip() + break + + if old_toolset and desired_toolset and old_toolset != desired_toolset: + print(f"[FIX] Removing stale CMake cache because toolset changed:") + print(f"[FIX] old = {old_toolset}") + print(f"[FIX] new = {desired_toolset}") + shutil.rmtree(build_temp, ignore_errors=True) + build_temp.mkdir(parents=True, exist_ok=True) + + +class CMakeExtension(Extension): + def __init__(self, name: str, sourcedir: str = "") -> None: + super().__init__(name, sources=[]) + self.sourcedir = _norm(Path(sourcedir or ".").resolve()) + + +class CMakeBuild(build_ext): + def run(self) -> None: + try: + subprocess.run(["cmake", "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except Exception as exc: + raise RuntimeError("CMake is required to build tetra-nerf") from exc + + for ext in self.extensions: + self.build_extension(ext) + + def build_extension(self, ext: CMakeExtension) -> None: + source_dir = Path(ext.sourcedir).resolve() + cfg = _detect_build_type() + + build_root = Path(self.build_temp or (ROOT / "build" / "cmake")).resolve() + build_temp = build_root if build_root.name.lower() == cfg.lower() else (build_root / cfg) + build_temp.mkdir(parents=True, exist_ok=True) + + python_exe = _norm(sys.executable) + cuda_mode = _discover_cuda_mode() + + cuda_root = _discover_cuda_root(cuda_mode) + nvcc = _discover_nvcc(cuda_root, cuda_mode) + optix_root = _discover_optix_root() + optix_include = _discover_optix_include(optix_root) + + generator = _discover_generator() + base_toolset = _discover_toolset() + prefixes = _torch_cmake_prefixes() + cmake_prefix_path = ";".join(prefixes) + + extdir = Path(self.get_ext_fullpath(ext.name)).resolve().parent + extdir.mkdir(parents=True, exist_ok=True) + + if not optix_include: + raise RuntimeError("OptiX headers not found. Set OPTIX_ROOT_DIR or OPTIX_INCLUDE_DIR correctly.") + + cl_path = _find_cl_from_env() + vctools_install_dir, vcinstalldir = _read_vcvars_paths() + + if not cl_path: + raise RuntimeError( + "cl.exe not found in environment. Run this build from a vcvars-initialized shell or through ns-installer bootstrap." + ) + + toolset = base_toolset + if "Visual Studio" in generator: + if not toolset and cuda_mode == "vanilla": + toolset = _default_vanilla_toolset(cuda_root) + elif toolset and "cuda=" not in toolset.lower(): + toolset = f"{toolset},cuda={cuda_root}" + elif not toolset and cuda_root: + toolset = f"cuda={cuda_root}" + + _ensure_clean_toolset_cache(build_temp, toolset) + + _print_info("source_dir", source_dir) + _print_info("build_temp", build_temp) + _print_info("cfg", cfg) + _print_info("python_executable", python_exe) + _print_info("cuda_mode", cuda_mode) + _print_info("generator", generator) + _print_info("toolset", toolset or "") + _print_info("cl_path", cl_path or "") + _print_info("VCToolsInstallDir", vctools_install_dir or "") + _print_info("VCINSTALLDIR", vcinstalldir or "") + _print_info("cuda_root", cuda_root or "") + _print_info("nvcc", nvcc or "") + _print_info("optix_root", optix_root or "") + _print_info("optix_include", optix_include or "") + _print_info("cmake_prefix_path", cmake_prefix_path or "") + + cmake_args = [ + "-S", _cmake_path(source_dir), + "-B", _cmake_path(build_temp), + f"-DPYTHON_EXECUTABLE={_cmake_path(python_exe)}", + f"-DCMAKE_BUILD_TYPE={cfg}", + f"-DEXAMPLE_VERSION_INFO={VERSION}", + f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={_cmake_path(extdir)}", + f"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY={_cmake_path(extdir)}", + f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE={_cmake_path(extdir)}", + f"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE={_cmake_path(extdir)}", + f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG={_cmake_path(extdir)}", + f"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG={_cmake_path(extdir)}", + f"-DCUDAToolkit_ROOT={_cmake_path(cuda_root)}", + f"-DCUDA_TOOLKIT_ROOT_DIR={_cmake_path(cuda_root)}", + f"-DCMAKE_CUDA_COMPILER={_cmake_path(nvcc)}", + f"-DCMAKE_C_COMPILER={_cmake_path(cl_path)}", + f"-DCMAKE_CXX_COMPILER={_cmake_path(cl_path)}", + f"-DOPTIX_ROOT_DIR={_cmake_path(optix_root)}", + f"-DOPTIX_INSTALL_DIR={_cmake_path(optix_root)}", + f"-DOPTIX_INCLUDE_DIR={_cmake_path(optix_include)}", + ] + + if cmake_prefix_path: + parts = [_cmake_path(p) for p in cmake_prefix_path.split(";") if p] + cmake_args.append(f"-DCMAKE_PREFIX_PATH={';'.join(parts)}") + + if generator: + cmake_args.extend(["-G", generator]) + + if "Visual Studio" in generator: + cmake_args.extend(["-A", "x64"]) + if toolset: + cmake_args.extend(["-T", toolset]) + + if _safe_env_bool("NS_FORCE_CUDA_11_8", default=(cuda_mode == "vanilla")): + cmake_args.append("-DNS_FORCE_CUDA_11_8=ON") + + build_args = [ + "--build", + _cmake_path(build_temp), + "--config", + cfg, + ] + + max_jobs = ( + os.environ.get("CMAKE_BUILD_PARALLEL_LEVEL", "").strip() + or os.environ.get("MAX_JOBS", "").strip() + ) + if max_jobs: + build_args.extend(["--parallel", max_jobs]) + + env = os.environ.copy() + + # remove duplicate keys that break MSBuild on Windows + _remove_env_keys_casefold( + env, + "VCToolsInstallDir", + "VCINSTALLDIR", + "CUDA_PATH", + "CUDA_HOME", + "CUDAToolkit_ROOT", + "CUDA_TOOLKIT_ROOT_DIR", + "CUDACXX", + "CC", + "CXX", + "OPTIX_ROOT_DIR", + "OPTIX_INSTALL_DIR", + "OPTIX_INCLUDE_DIR", + "ROCM_HOME", + "ROCM_PATH", + "HIP_HOME", + "HIP_PATH", + "HIP_ROOT_DIR", + "HSA_PATH", + "MIOPEN_PATH", + "HIP_PLATFORM", + "HIP_COMPILER", + "HCC_AMDGPU_TARGET", + "PYTORCH_ROCM_ARCH", + "HCC_HOME", + "HIP_PATH_57", + "HIP_DEVICE_LIB_PATH", + ) + + if vctools_install_dir: + env["VCToolsInstallDir"] = vctools_install_dir + if vcinstalldir: + env["VCINSTALLDIR"] = vcinstalldir + + env["CUDA_PATH"] = cuda_root + env["CUDA_HOME"] = cuda_root + env["CUDAToolkit_ROOT"] = cuda_root + env["CUDA_TOOLKIT_ROOT_DIR"] = cuda_root + env["CUDACXX"] = nvcc + + env["CC"] = cl_path + env["CXX"] = cl_path + + if optix_root: + env["OPTIX_ROOT_DIR"] = optix_root + env["OPTIX_INSTALL_DIR"] = optix_root + if optix_include: + env["OPTIX_INCLUDE_DIR"] = optix_include + + cuda_bin = _norm(Path(cuda_root) / "bin") + cuda_libnvvp = _norm(Path(cuda_root) / "libnvvp") + cl_dir = _norm(Path(cl_path).parent) + + old_path_parts = env.get("PATH", "").split(os.pathsep) + filtered = _clean_cuda_path_entries(old_path_parts, cuda_root, cuda_mode) + env["PATH"] = os.pathsep.join(_dedupe_paths([cl_dir, cuda_bin, cuda_libnvvp] + filtered)) + + subprocess.run(["cmake", *cmake_args], cwd=str(source_dir), env=env, check=True) + subprocess.run(["cmake", *build_args], cwd=str(source_dir), env=env, check=True) + + # Try to locate the built extension and copy it into the Python package. + built_candidates = [ + build_temp / "Release" / f"{ext.name}.cp{sys.version_info.major}{sys.version_info.minor}-win_amd64.pyd", + build_temp / "lib" / "Release" / f"{ext.name}.cp{sys.version_info.major}{sys.version_info.minor}-win_amd64.pyd", + ROOT / "build" / f"lib.win-amd64-cpython-{sys.version_info.major}{sys.version_info.minor}" / f"{ext.name}.cp{sys.version_info.major}{sys.version_info.minor}-win_amd64.pyd", + ROOT / f"{ext.name}.cp{sys.version_info.major}{sys.version_info.minor}-win_amd64.pyd", + ] + + built_pyd = None + for candidate in built_candidates: + if candidate.exists(): + built_pyd = candidate + break + + if built_pyd is None: + matches = list(ROOT.rglob(f"{ext.name}.cp{sys.version_info.major}{sys.version_info.minor}-win_amd64.pyd")) + if matches: + built_pyd = matches[0] + + if built_pyd is None: + raise RuntimeError(f"Built extension {ext.name} was not found after build.") + + package_ext_dir = ROOT / "tetranerf" / "utils" / "extension" + package_ext_dir.mkdir(parents=True, exist_ok=True) + + final_pyd = package_ext_dir / built_pyd.name + shutil.copy2(built_pyd, final_pyd) + _print_info("copied_extension", final_pyd) + + # Windows multi-config fallback: move pyd from Release/Debug to importable extdir + for sub in ["Release", "Debug"]: + subdir = extdir / sub + if subdir.exists(): + for pyd in subdir.glob("*.pyd"): + target = extdir / pyd.name + print(f"[FIX] moving {pyd} -> {target}") + if target.exists(): + target.unlink() + shutil.move(str(pyd), str(target)) + + +setup( + name=PKG_NAME, + version=VERSION, + packages=find_packages(include=["tetranerf", "tetranerf.*"]), + include_package_data=True, + ext_modules=[CMakeExtension("tetranerf_cpp_extension", sourcedir=str(ROOT))], + cmdclass={"build_ext": CMakeBuild}, + zip_safe=False, +) \ No newline at end of file diff --git a/Extra-Methods-Patches/tetra-nerf/setup.py.almost-good b/Extra-Methods-Patches/tetra-nerf/setup.py.almost-good new file mode 100644 index 0000000000..4a87df5572 --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/setup.py.almost-good @@ -0,0 +1,488 @@ +from __future__ import annotations + +import os +import shutil +import subprocess +import sys +from pathlib import Path + +from setuptools import Extension, setup +from setuptools.command.build_ext import build_ext + + +ROOT = Path(__file__).resolve().parent +PKG_NAME = "tetra-nerf" +VERSION = "0.1.1" + +VANILLA_CUDA_VERSION = "11.8" +VANILLA_MSVC_TOOLSET = "14.38.33130" +VANILLA_MSVC_MAJOR = "v143" + + +def _norm(p: str | Path | None) -> str: + if not p: + return "" + return os.path.normpath(str(p)) + + +def _cmake_path(p: str | Path | None) -> str: + return _norm(p).replace("\\", "/") + + +def _existing_dir(*candidates: str | Path | None) -> str: + for c in candidates: + if not c: + continue + p = Path(str(c)) + if p.exists() and p.is_dir(): + return _norm(p) + return "" + + +def _existing_file(*candidates: str | Path | None) -> str: + for c in candidates: + if not c: + continue + p = Path(str(c)) + if p.exists() and p.is_file(): + return _norm(p) + return "" + + +def _safe_env_bool(name: str, default: bool = False) -> bool: + v = os.environ.get(name, "").strip().lower() + if not v: + return default + return v in {"1", "true", "yes", "on"} + + +def _print_info(label: str, value: object) -> None: + print(f"[INFO] {label} = {value}") + + +def _dedupe_paths(parts: list[str]) -> list[str]: + out: list[str] = [] + seen: set[str] = set() + for p in parts: + if not p: + continue + pn = _norm(p) + key = pn.lower() + if key in seen: + continue + seen.add(key) + out.append(pn) + return out + + +def _remove_env_keys_casefold(env: dict[str, str], *keys: str) -> None: + wanted = {k.casefold() for k in keys} + to_del = [k for k in list(env.keys()) if k.casefold() in wanted] + for k in to_del: + env.pop(k, None) + + +def _clean_cuda_path_entries(old_parts: list[str], selected_cuda_root: str, cuda_mode: str) -> list[str]: + selected_cuda_root_norm = _norm(selected_cuda_root).lower() + out: list[str] = [] + + for p in old_parts: + pn = _norm(p) + if not pn: + continue + low = pn.lower() + + # in vanilla, keep only the selected CUDA tree + if "nvidia gpu computing toolkit" in low and "\\cuda\\" in low: + if cuda_mode == "vanilla": + if not low.startswith(selected_cuda_root_norm): + continue + + # purge ROCm/HIP noise that breaks torch cpp_extension on Windows + if any(token in low for token in [ + "\\rocm\\", + "\\hip\\", + "amd\\rocm", + "rocm\\bin", + "hip\\bin", + ]): + continue + + out.append(pn) + + return _dedupe_paths(out) + + +def _discover_cuda_mode() -> str: + mode = os.environ.get("NS_CUDA_MODE", "").strip().lower() + if mode in {"vanilla", "experimental-env"}: + return mode + return "vanilla" + + +def _vanilla_cuda_root_candidate() -> Path: + return Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA GPU Computing Toolkit" / "CUDA" / f"v{VANILLA_CUDA_VERSION}" + + +def _discover_cuda_root(cuda_mode: str) -> str: + vanilla_candidates = [ + _vanilla_cuda_root_candidate(), + os.environ.get("CUDAToolkit_ROOT"), + os.environ.get("CUDA_HOME"), + os.environ.get("CUDA_PATH"), + ] + + experimental_candidates = [ + os.environ.get("CUDAToolkit_ROOT"), + os.environ.get("CUDA_HOME"), + os.environ.get("CUDA_PATH"), + _vanilla_cuda_root_candidate(), + ] + + candidates = vanilla_candidates if cuda_mode == "vanilla" else experimental_candidates + cuda_root = _existing_dir(*candidates) + if not cuda_root: + raise RuntimeError("CUDA toolkit root not found.") + return cuda_root + + +def _discover_nvcc(cuda_root: str, cuda_mode: str) -> str: + root_nvcc = Path(cuda_root) / "bin" / "nvcc.exe" + if root_nvcc.exists(): + return _norm(root_nvcc) + + if cuda_mode == "experimental-env": + nvcc = shutil.which("nvcc.exe") or shutil.which("nvcc") + if nvcc: + return _norm(nvcc) + + raise RuntimeError("nvcc not found under selected CUDA toolkit.") + + +def _discover_optix_root() -> str: + candidates = [ + os.environ.get("OPTIX_ROOT_DIR"), + os.environ.get("OPTIX_INSTALL_DIR"), + os.environ.get("OPTIX_PATH"), + os.environ.get("OPTIX_HOME"), + Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA Corporation" / "OptiX SDK 9.1.0", + Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA Corporation" / "OptiX SDK 9.0.0", + Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA Corporation" / "OptiX SDK 8.1.0", + Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA Corporation" / "OptiX SDK 8.0.0", + ] + return _existing_dir(*candidates) + + +def _discover_optix_include(optix_root: str) -> str: + candidates = [ + os.environ.get("OPTIX_INCLUDE_DIR"), + ] + if optix_root: + candidates.insert(0, str(Path(optix_root) / "include")) + candidates.insert(1, optix_root) + + include_dir = _existing_dir(*candidates) + if include_dir and (Path(include_dir) / "optix.h").exists(): + return include_dir + return "" + + +def _torch_cmake_prefixes() -> list[str]: + prefixes: list[str] = [] + + conda_prefix = os.environ.get("CONDA_PREFIX", "") + if conda_prefix: + prefixes.append(_norm(Path(conda_prefix))) + prefixes.append(_norm(Path(conda_prefix) / "Library")) + prefixes.append(_norm(Path(conda_prefix) / "Lib")) + prefixes.append(_norm(Path(conda_prefix) / "lib" / "site-packages")) + + try: + import torch # type: ignore + + torch_dir = Path(torch.__file__).resolve().parent + prefixes.append(_norm(torch_dir)) + prefixes.append(_norm(torch_dir.parent)) + except Exception: + pass + + return _dedupe_paths(prefixes) + + +def _discover_generator() -> str: + return os.environ.get("CMAKE_GENERATOR", "Visual Studio 17 2022").strip() or "Visual Studio 17 2022" + + +def _discover_toolset() -> str: + explicit = os.environ.get("CMAKE_GENERATOR_TOOLSET", "").strip() + if explicit: + return explicit + return "" + + +def _default_vanilla_toolset(cuda_root: str) -> str: + return f"{VANILLA_MSVC_MAJOR},version={VANILLA_MSVC_TOOLSET},cuda={cuda_root}" + + +def _detect_build_type() -> str: + return "Debug" if os.environ.get("DEBUG", "0") == "1" else "Release" + + +def _find_cl_from_env() -> str: + vctools = _norm(os.environ.get("VCToolsInstallDir")) + if vctools: + candidate = Path(vctools) / "bin" / "Hostx64" / "x64" / "cl.exe" + if candidate.exists(): + return _norm(candidate) + + candidates = [ + os.environ.get("CMAKE_CXX_COMPILER"), + os.environ.get("CXX"), + os.environ.get("CC"), + shutil.which("cl.exe"), + ] + return _existing_file(*candidates) + + +def _read_vcvars_paths() -> tuple[str, str]: + vctools = _norm(os.environ.get("VCToolsInstallDir")) + vcinst = _norm(os.environ.get("VCINSTALLDIR")) + return vctools, vcinst + + +def _ensure_clean_toolset_cache(build_temp: Path, desired_toolset: str) -> None: + cache_file = build_temp / "CMakeCache.txt" + if not cache_file.exists(): + return + + try: + text = cache_file.read_text(encoding="utf-8", errors="ignore") + except Exception: + text = "" + + old_toolset = "" + for line in text.splitlines(): + if line.startswith("CMAKE_GENERATOR_TOOLSET:INTERNAL=") or line.startswith("CMAKE_GENERATOR_TOOLSET:STRING="): + old_toolset = line.split("=", 1)[1].strip() + break + + if old_toolset and desired_toolset and old_toolset != desired_toolset: + print(f"[FIX] Removing stale CMake cache because toolset changed:") + print(f"[FIX] old = {old_toolset}") + print(f"[FIX] new = {desired_toolset}") + shutil.rmtree(build_temp, ignore_errors=True) + build_temp.mkdir(parents=True, exist_ok=True) + + +class CMakeExtension(Extension): + def __init__(self, name: str, sourcedir: str = "") -> None: + super().__init__(name, sources=[]) + self.sourcedir = _norm(Path(sourcedir or ".").resolve()) + + +class CMakeBuild(build_ext): + def run(self) -> None: + try: + subprocess.run(["cmake", "--version"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except Exception as exc: + raise RuntimeError("CMake is required to build tetra-nerf") from exc + + for ext in self.extensions: + self.build_extension(ext) + + def build_extension(self, ext: CMakeExtension) -> None: + source_dir = Path(ext.sourcedir).resolve() + cfg = _detect_build_type() + + build_root = Path(self.build_temp or (ROOT / "build" / "cmake")).resolve() + build_temp = build_root if build_root.name.lower() == cfg.lower() else (build_root / cfg) + build_temp.mkdir(parents=True, exist_ok=True) + + python_exe = _norm(sys.executable) + cuda_mode = _discover_cuda_mode() + + cuda_root = _discover_cuda_root(cuda_mode) + nvcc = _discover_nvcc(cuda_root, cuda_mode) + optix_root = _discover_optix_root() + optix_include = _discover_optix_include(optix_root) + + generator = _discover_generator() + base_toolset = _discover_toolset() + prefixes = _torch_cmake_prefixes() + cmake_prefix_path = ";".join(prefixes) + + extdir = Path(self.get_ext_fullpath(ext.name)).resolve().parent + extdir.mkdir(parents=True, exist_ok=True) + + if not optix_include: + raise RuntimeError("OptiX headers not found. Set OPTIX_ROOT_DIR or OPTIX_INCLUDE_DIR correctly.") + + cl_path = _find_cl_from_env() + vctools_install_dir, vcinstalldir = _read_vcvars_paths() + + if not cl_path: + raise RuntimeError( + "cl.exe not found in environment. Run this build from a vcvars-initialized shell or through ns-installer bootstrap." + ) + + toolset = base_toolset + if "Visual Studio" in generator: + if not toolset and cuda_mode == "vanilla": + toolset = _default_vanilla_toolset(cuda_root) + elif toolset and "cuda=" not in toolset.lower(): + toolset = f"{toolset},cuda={cuda_root}" + elif not toolset and cuda_root: + toolset = f"cuda={cuda_root}" + + _ensure_clean_toolset_cache(build_temp, toolset) + + _print_info("source_dir", source_dir) + _print_info("build_temp", build_temp) + _print_info("cfg", cfg) + _print_info("python_executable", python_exe) + _print_info("cuda_mode", cuda_mode) + _print_info("generator", generator) + _print_info("toolset", toolset or "") + _print_info("cl_path", cl_path or "") + _print_info("VCToolsInstallDir", vctools_install_dir or "") + _print_info("VCINSTALLDIR", vcinstalldir or "") + _print_info("cuda_root", cuda_root or "") + _print_info("nvcc", nvcc or "") + _print_info("optix_root", optix_root or "") + _print_info("optix_include", optix_include or "") + _print_info("cmake_prefix_path", cmake_prefix_path or "") + + cmake_args = [ + "-S", _cmake_path(source_dir), + "-B", _cmake_path(build_temp), + f"-DPYTHON_EXECUTABLE={_cmake_path(python_exe)}", + f"-DCMAKE_BUILD_TYPE={cfg}", + f"-DEXAMPLE_VERSION_INFO={VERSION}", + f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={_cmake_path(extdir)}", + f"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY={_cmake_path(extdir)}", + f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE={_cmake_path(extdir)}", + f"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE={_cmake_path(extdir)}", + f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG={_cmake_path(extdir)}", + f"-DCMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG={_cmake_path(extdir)}", + f"-DCUDAToolkit_ROOT={_cmake_path(cuda_root)}", + f"-DCUDA_TOOLKIT_ROOT_DIR={_cmake_path(cuda_root)}", + f"-DCMAKE_CUDA_COMPILER={_cmake_path(nvcc)}", + f"-DCMAKE_C_COMPILER={_cmake_path(cl_path)}", + f"-DCMAKE_CXX_COMPILER={_cmake_path(cl_path)}", + f"-DOPTIX_ROOT_DIR={_cmake_path(optix_root)}", + f"-DOPTIX_INSTALL_DIR={_cmake_path(optix_root)}", + f"-DOPTIX_INCLUDE_DIR={_cmake_path(optix_include)}", + ] + + if cmake_prefix_path: + parts = [_cmake_path(p) for p in cmake_prefix_path.split(";") if p] + cmake_args.append(f"-DCMAKE_PREFIX_PATH={';'.join(parts)}") + + if generator: + cmake_args.extend(["-G", generator]) + + if "Visual Studio" in generator: + cmake_args.extend(["-A", "x64"]) + if toolset: + cmake_args.extend(["-T", toolset]) + + if _safe_env_bool("NS_FORCE_CUDA_11_8", default=(cuda_mode == "vanilla")): + cmake_args.append("-DNS_FORCE_CUDA_11_8=ON") + + build_args = [ + "--build", + _cmake_path(build_temp), + "--config", + cfg, + ] + + max_jobs = ( + os.environ.get("CMAKE_BUILD_PARALLEL_LEVEL", "").strip() + or os.environ.get("MAX_JOBS", "").strip() + ) + if max_jobs: + build_args.extend(["--parallel", max_jobs]) + + env = os.environ.copy() + + # remove duplicate keys that break MSBuild on Windows + _remove_env_keys_casefold( + env, + "VCToolsInstallDir", + "VCINSTALLDIR", + "CUDA_PATH", + "CUDA_HOME", + "CUDAToolkit_ROOT", + "CUDA_TOOLKIT_ROOT_DIR", + "CUDACXX", + "CC", + "CXX", + "OPTIX_ROOT_DIR", + "OPTIX_INSTALL_DIR", + "OPTIX_INCLUDE_DIR", + "ROCM_HOME", + "ROCM_PATH", + "HIP_HOME", + "HIP_PATH", + "HIP_ROOT_DIR", + "HSA_PATH", + "MIOPEN_PATH", + "HIP_PLATFORM", + "HIP_COMPILER", + "HCC_AMDGPU_TARGET", + "PYTORCH_ROCM_ARCH", + "HCC_HOME", + "HIP_PATH_57", + "HIP_DEVICE_LIB_PATH", + ) + + if vctools_install_dir: + env["VCToolsInstallDir"] = vctools_install_dir + if vcinstalldir: + env["VCINSTALLDIR"] = vcinstalldir + + env["CUDA_PATH"] = cuda_root + env["CUDA_HOME"] = cuda_root + env["CUDAToolkit_ROOT"] = cuda_root + env["CUDA_TOOLKIT_ROOT_DIR"] = cuda_root + env["CUDACXX"] = nvcc + + env["CC"] = cl_path + env["CXX"] = cl_path + + if optix_root: + env["OPTIX_ROOT_DIR"] = optix_root + env["OPTIX_INSTALL_DIR"] = optix_root + if optix_include: + env["OPTIX_INCLUDE_DIR"] = optix_include + + cuda_bin = _norm(Path(cuda_root) / "bin") + cuda_libnvvp = _norm(Path(cuda_root) / "libnvvp") + cl_dir = _norm(Path(cl_path).parent) + + old_path_parts = env.get("PATH", "").split(os.pathsep) + filtered = _clean_cuda_path_entries(old_path_parts, cuda_root, cuda_mode) + env["PATH"] = os.pathsep.join(_dedupe_paths([cl_dir, cuda_bin, cuda_libnvvp] + filtered)) + + subprocess.run(["cmake", *cmake_args], cwd=str(source_dir), env=env, check=True) + subprocess.run(["cmake", *build_args], cwd=str(source_dir), env=env, check=True) + + # Windows multi-config fallback: move pyd from Release/Debug to importable extdir + for sub in ["Release", "Debug"]: + subdir = extdir / sub + if subdir.exists(): + for pyd in subdir.glob("*.pyd"): + target = extdir / pyd.name + print(f"[FIX] moving {pyd} -> {target}") + if target.exists(): + target.unlink() + shutil.move(str(pyd), str(target)) + + +setup( + name=PKG_NAME, + version=VERSION, + ext_modules=[CMakeExtension("tetranerf_cpp_extension", sourcedir=str(ROOT))], + cmdclass={"build_ext": CMakeBuild}, + zip_safe=False, +) \ No newline at end of file diff --git a/Extra-Methods-Patches/tetra-nerf/src/py_binding.cpp b/Extra-Methods-Patches/tetra-nerf/src/py_binding.cpp new file mode 100644 index 0000000000..1b8325f4c4 --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/src/py_binding.cpp @@ -0,0 +1,476 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "tetrahedra_tracer.h" +#include "triangulation.h" +#include "utils/exception.h" + +namespace py = pybind11; +using namespace pybind11::literals; // to bring in the `_a` literal + +#define CHECK_CUDA(x) TORCH_CHECK(x.device().is_cuda(), #x " must be a CUDA tensor") +#define CHECK_DEVICE(x) TORCH_CHECK(x.device() == this->device, #x " must be on the same device") +#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x " must be contiguous") +#define CHECK_FLOAT(x) TORCH_CHECK(x.dtype() == torch::kFloat32, #x " must have float32 type") +#define CHECK_INPUT(x) \ + CHECK_CUDA(x); \ + CHECK_CONTIGUOUS(x) +#define CHECK_FLOAT_DIM3(x) \ + CHECK_INPUT(x); \ + CHECK_DEVICE(x); \ + CHECK_FLOAT(x); \ + TORCH_CHECK(x.size(-1) == 3, #x " must have last dimension with size 3") + +struct PyTetrahedraTracer { + public: + PyTetrahedraTracer(const torch::Device &device) : device(device) { + if (!device.is_cuda()) { + throw Exception("The device argument must be a CUDA device."); + } + tracer = std::make_unique(device.index()); + } + + ~PyTetrahedraTracer() { + tracer.reset(); + tetrahedra_cells.reset(); + tetrahedra_vertices.reset(); + } + + py::dict trace_rays(const torch::Tensor &ray_origins, + const torch::Tensor &ray_directions, + const unsigned long max_ray_triangles) { + if ((max_ray_triangles & (max_ray_triangles - 1)) != 0) { + throw Exception("max_ray_triangles must be a power of 2."); + } + + torch::AutoGradMode enable_grad(false); + CHECK_FLOAT_DIM3(ray_origins); + CHECK_FLOAT_DIM3(ray_directions); + const size_t num_rays = ray_origins.numel() / 3; + + const auto num_visited_cells = + torch::zeros({(long)num_rays}, torch::device(device).dtype(torch::kInt32)); + const auto visited_cells = + torch::zeros({(long)num_rays, (long)max_ray_triangles}, torch::device(device).dtype(torch::kInt32)); + const auto barycentric_coordinates = + torch::zeros({(long)num_rays, (long)max_ray_triangles, 2, 3}, torch::device(device).dtype(torch::kFloat32)); + const auto hit_distances = + torch::zeros({(long)num_rays, (long)max_ray_triangles, 2}, torch::device(device).dtype(torch::kFloat32)); + const auto vertex_indices = + torch::zeros({(long)num_rays, (long)max_ray_triangles, 4}, torch::device(device).dtype(torch::kInt32)); + + tracer->trace_rays( + num_rays, + max_ray_triangles, + reinterpret_cast(ray_origins.data_ptr()), + reinterpret_cast(ray_directions.data_ptr()), + reinterpret_cast(num_visited_cells.data_ptr()), + reinterpret_cast(visited_cells.data_ptr()), + reinterpret_cast(barycentric_coordinates.data_ptr()), + reinterpret_cast(hit_distances.data_ptr()), + reinterpret_cast(vertex_indices.data_ptr())); + + return py::dict( + "num_visited_cells"_a = num_visited_cells, + "visited_cells"_a = visited_cells, + "barycentric_coordinates"_a = barycentric_coordinates, + "vertex_indices"_a = vertex_indices, + "hit_distances"_a = hit_distances); + } + + py::dict trace_rays_triangles(const torch::Tensor &ray_origins, + const torch::Tensor &ray_directions, + const unsigned long max_ray_triangles) { + if ((max_ray_triangles & (max_ray_triangles - 1)) != 0) { + throw Exception("max_ray_triangles must be a power of 2."); + } + + torch::AutoGradMode enable_grad(false); + CHECK_FLOAT_DIM3(ray_origins); + CHECK_FLOAT_DIM3(ray_directions); + const size_t num_rays = ray_origins.numel() / 3; + + const auto num_visited_triangles = + torch::zeros({(long)num_rays}, torch::device(device).dtype(torch::kInt32)); + const auto visited_triangles = + torch::zeros({(long)num_rays, (long)max_ray_triangles}, torch::device(device).dtype(torch::kInt32)); + const auto barycentric_coordinates = + torch::zeros({(long)num_rays, (long)max_ray_triangles, 2}, torch::device(device).dtype(torch::kFloat32)); + const auto hit_distances = + torch::zeros({(long)num_rays, (long)max_ray_triangles}, torch::device(device).dtype(torch::kFloat32)); + const auto vertex_indices = + torch::zeros({(long)num_rays, (long)max_ray_triangles, 3}, torch::device(device).dtype(torch::kInt32)); + + tracer->trace_rays_triangles( + num_rays, + max_ray_triangles, + reinterpret_cast(ray_origins.data_ptr()), + reinterpret_cast(ray_directions.data_ptr()), + reinterpret_cast(num_visited_triangles.data_ptr()), + reinterpret_cast(visited_triangles.data_ptr()), + reinterpret_cast(barycentric_coordinates.data_ptr()), + reinterpret_cast(hit_distances.data_ptr()), + reinterpret_cast(vertex_indices.data_ptr())); + + return py::dict( + "num_visited_triangles"_a = num_visited_triangles, + "visited_triangles"_a = visited_triangles, + "barycentric_coordinates"_a = barycentric_coordinates, + "vertex_indices"_a = vertex_indices, + "hit_distances"_a = hit_distances); + } + + py::dict find_tetrahedra(const torch::Tensor &positions) { + torch::AutoGradMode enable_grad(false); + CHECK_FLOAT_DIM3(positions); + const size_t num_points = positions.numel() / 3; + auto shape = positions.sizes().vec(); + + const auto barycentric_coordinates = + torch::zeros(shape, torch::device(device).dtype(torch::kFloat32)); + + shape.pop_back(); + shape.push_back(4); + const auto vertex_indices = + torch::zeros(shape, torch::device(device).dtype(torch::kInt32)); + + shape.pop_back(); + const auto tetrahedra = + torch::zeros(shape, torch::device(device).dtype(torch::kInt32)); + + tracer->find_tetrahedra( + num_points, + reinterpret_cast(positions.data_ptr()), + reinterpret_cast(tetrahedra.data_ptr()), + reinterpret_cast(barycentric_coordinates.data_ptr()), + reinterpret_cast(vertex_indices.data_ptr())); + + return py::dict( + "tetrahedra"_a = tetrahedra, + "barycentric_coordinates"_a = barycentric_coordinates, + "vertex_indices"_a = vertex_indices, + "valid_mask"_a = tetrahedra != -1); + } + + void load_tetrahedra(const torch::Tensor &xyz, const torch::Tensor &cells) { + CHECK_FLOAT_DIM3(xyz); + CHECK_INPUT(cells); + CHECK_DEVICE(cells); + TORCH_CHECK(cells.size(-1) == 4, "indices must have last dimension with size 4"); + TORCH_CHECK(cells.dtype() == torch::kInt32, "indices must have int32 type"); + + this->tetrahedra_cells = cells; + this->tetrahedra_vertices = xyz; + + tracer->load_tetrahedra( + tetrahedra_vertices.value().numel() / 3, + tetrahedra_cells.value().numel() / 4, + reinterpret_cast(tetrahedra_vertices.value().data_ptr()), + reinterpret_cast(tetrahedra_cells.value().data_ptr())); + } + + py::dict find_visited_cells(const torch::Tensor &num_visited_cells, + const torch::Tensor &visited_cells, + const torch::Tensor &barycentric_coordinates, + const torch::Tensor &hit_distances, + const torch::Tensor &vertex_indices, + const torch::Tensor &distances) { + CHECK_INPUT(num_visited_cells); + CHECK_DEVICE(num_visited_cells); + CHECK_INPUT(visited_cells); + CHECK_DEVICE(visited_cells); + CHECK_INPUT(barycentric_coordinates); + CHECK_DEVICE(barycentric_coordinates); + CHECK_INPUT(hit_distances); + CHECK_DEVICE(hit_distances); + CHECK_INPUT(distances); + CHECK_DEVICE(distances); + CHECK_INPUT(vertex_indices); + CHECK_DEVICE(vertex_indices); + + TORCH_CHECK(distances.dtype() == torch::kFloat32, "distances must have float32 type"); + const size_t num_rays = num_visited_cells.size(0); + TORCH_CHECK( + distances.dim() == 2 && distances.size(0) == num_rays, + "distances must be of [num_rays, num_samples_per_ray] shape"); + TORCH_CHECK(vertex_indices.size(-1) == 4, "vertex_indices must have last dimension with size 4"); + + const size_t num_samples_per_ray = distances.size(-1); + + const auto mask = + torch::full({(long)num_rays, (long)num_samples_per_ray}, 0, torch::device(device).dtype(torch::kBool)); + const auto matched_cells = + torch::full({(long)num_rays, (long)num_samples_per_ray}, -1, torch::device(device).dtype(torch::kInt32)); + const auto barycentric_coordinates_out = + torch::zeros({(long)num_rays, (long)num_samples_per_ray, 3}, torch::device(device).dtype(torch::kFloat32)); + const auto vertex_indices_out = + torch::full({(long)num_rays, (long)num_samples_per_ray, 4}, -1, torch::device(device).dtype(torch::kInt32)); + + find_matched_cells( + num_rays, + num_samples_per_ray, + visited_cells.size(1), + reinterpret_cast(tetrahedra_cells.value().data_ptr()), + reinterpret_cast(num_visited_cells.data_ptr()), + reinterpret_cast(visited_cells.data_ptr()), + reinterpret_cast(hit_distances.data_ptr()), + reinterpret_cast(barycentric_coordinates.data_ptr()), + reinterpret_cast(distances.data_ptr()), + reinterpret_cast(vertex_indices.data_ptr()), + reinterpret_cast(matched_cells.data_ptr()), + reinterpret_cast(vertex_indices_out.data_ptr()), + reinterpret_cast(mask.data_ptr()), + reinterpret_cast(barycentric_coordinates_out.data_ptr())); + + return py::dict( + "cell_indices"_a = matched_cells, + "vertex_indices"_a = vertex_indices_out, + "mask"_a = mask, + "barycentric_coordinates"_a = barycentric_coordinates_out); + } + + const torch::Device &get_device() const { + return this->device; + } + + private: + std::unique_ptr tracer; + torch::Device device; + std::optional tetrahedra_vertices; + std::optional tetrahedra_cells; +}; + +float py_find_average_spacing(const torch::Tensor &points) { + CHECK_CONTIGUOUS(points); + TORCH_CHECK(points.device().is_cpu(), "points must be a CPU tensor"); + TORCH_CHECK(points.dim() == 2 && points.size(1) == 3, "points must have shape [num_points, 3]"); + + return find_average_spacing( + points.size(0), + reinterpret_cast(points.data_ptr())); +} + +torch::Tensor py_triangulate(const torch::Tensor &points) { + TORCH_CHECK(points.dim() == 2 && points.size(1) == 3, "points must have shape [num_points, 3]"); + const auto points_ = points.cpu().contiguous(); + + std::vector cells = triangulate( + points_.size(0), + reinterpret_cast(points_.data_ptr())); + + if (cells.size() >= static_cast(std::numeric_limits::max())) { + throw Exception("Too many points!"); + } + + auto cells_out = torch::empty({(long)cells.size(), 4}, torch::dtype(torch::kInt32).device(torch::kCPU)); + memcpy( + cells_out.data_ptr(), + reinterpret_cast(cells.data()), + cells.size() * sizeof(uint4)); + return cells_out.to(points.device()); +} + +template +inline void call_dynamic_interpolate_values(uint32_t interpolation_dim, Types... args) { + switch (interpolation_dim) { + case 2: + interpolate_values<2>(args...); + break; + case 3: + interpolate_values<3>(args...); + break; + case 4: + interpolate_values<4>(args...); + break; + case 6: + interpolate_values<6>(args...); + break; + default: + throw Exception(("Unsupported interpolation dimension with value " + std::to_string(interpolation_dim)).c_str()); + } +} + +template +inline void call_dynamic_interpolate_values_backward(uint32_t interpolation_dim, Types... args) { + switch (interpolation_dim) { + case 2: + interpolate_values_backward<2>(args...); + break; + case 3: + interpolate_values_backward<3>(args...); + break; + case 4: + interpolate_values_backward<4>(args...); + break; + case 6: + interpolate_values_backward<6>(args...); + break; + default: + throw Exception(("Unsupported interpolation dimension with value " + std::to_string(interpolation_dim)).c_str()); + } +} + +torch::Tensor py_interpolate_values(const torch::Tensor &vertex_indices, + const torch::Tensor &barycentric_coordinates, + const torch::Tensor &field) { + CHECK_INPUT(vertex_indices); + CHECK_INPUT(barycentric_coordinates); + CHECK_INPUT(field); + + TORCH_CHECK(vertex_indices.dtype() == torch::kInt32, "vertex_indices must be a tensor of type int32"); + TORCH_CHECK(barycentric_coordinates.dtype() == torch::kFloat32, "barycentric_coordinates must be a tensor of type float32"); + TORCH_CHECK(barycentric_coordinates.size(-1) + 1 == vertex_indices.size(-1), + "barycentric_coordinates must have the same last dimension as vertex_indices - 1"); + TORCH_CHECK(field.dtype() == torch::kFloat32, "field must be a tensor of type float32"); + + const uint32_t interpolation_dim = static_cast(vertex_indices.size(-1)); + const uint32_t num_values = static_cast(vertex_indices.numel() / interpolation_dim); + const uint32_t field_dim = static_cast(field.size(0)); + const uint32_t num_vertices = static_cast(field.size(-1)); + + auto result_shape = vertex_indices.sizes().vec(); + result_shape.pop_back(); + result_shape.insert(result_shape.begin(), field_dim); + + const auto result = torch::empty(result_shape, torch::device(field.device()).dtype(field.dtype())); + + call_dynamic_interpolate_values( + interpolation_dim, + num_vertices, + num_values, + field_dim, + reinterpret_cast(vertex_indices.data_ptr()), + reinterpret_cast(barycentric_coordinates.data_ptr()), + reinterpret_cast(field.data_ptr()), + reinterpret_cast(result.data_ptr())); + + return result.moveaxis(0, -1); +} + +torch::Tensor py_interpolate_values_backward(const torch::Tensor &vertex_indices, + const torch::Tensor &barycentric_coordinates, + const torch::Tensor &field, + const torch::Tensor &grad_in) { + CHECK_INPUT(vertex_indices); + CHECK_INPUT(barycentric_coordinates); + CHECK_INPUT(field); + CHECK_INPUT(grad_in); + + TORCH_CHECK(vertex_indices.dtype() == torch::kInt32, "vertex_indices must be a tensor of type int32"); + TORCH_CHECK(barycentric_coordinates.dtype() == torch::kFloat32, "barycentric_coordinates must be a tensor of type float32"); + TORCH_CHECK(field.dtype() == torch::kFloat32, "field must be a tensor of type float32"); + TORCH_CHECK(grad_in.dtype() == torch::kFloat32, "grad_in must be a tensor of type float32"); + TORCH_CHECK(barycentric_coordinates.size(-1) + 1 == vertex_indices.size(-1), + "barycentric_coordinates must have the same last dimension as vertex_indices - 1"); + + const uint32_t interpolation_dim = static_cast(vertex_indices.size(-1)); + const uint32_t num_values = static_cast(vertex_indices.numel() / interpolation_dim); + const uint32_t field_dim = static_cast(field.size(0)); + const uint32_t num_vertices = static_cast(field.size(-1)); + + TORCH_CHECK(grad_in.size(-1) == field_dim, "grad_in must have shape [..., field_dim]"); + + const auto grad_field_out = + torch::zeros({(long)field_dim, (long)num_vertices}, torch::device(grad_in.device()).dtype(grad_in.dtype())); + + auto grad_in_moved = grad_in.moveaxis(-1, 0).contiguous(); + + call_dynamic_interpolate_values_backward( + interpolation_dim, + num_vertices, + num_values, + field_dim, + reinterpret_cast(vertex_indices.data_ptr()), + reinterpret_cast(barycentric_coordinates.data_ptr()), + reinterpret_cast(grad_in_moved.data_ptr()), + reinterpret_cast(grad_field_out.data_ptr())); + + return grad_field_out; +} + +torch::Tensor py_gather_uint32(const torch::Tensor &self, const uint32_t dim, const torch::Tensor &index) { + TORCH_CHECK(index.dtype() == torch::kInt32, "index must be a tensor of type int32"); + TORCH_CHECK(self.is_floating_point(), "self must be a tensor of a floating-point type"); + TORCH_CHECK(self.device() == index.device(), "self and index must be on the same device"); + TORCH_CHECK(self.is_contiguous(), "self must be contiguous"); + TORCH_CHECK(index.is_contiguous(), "index must be contiguous"); + TORCH_CHECK(self.is_cuda(), "self must be on CUDA"); + TORCH_CHECK(index.is_cuda(), "index must be on CUDA"); + TORCH_CHECK(self.dim() == 1, "self must be 1-dimensional"); + TORCH_CHECK(index.dim() == self.dim(), "self and index must have the same number of dimensions"); + TORCH_CHECK(dim == 0, "dim must be 0"); + + const auto result_shape = index.sizes(); + auto result = torch::empty(result_shape, torch::device(self.device()).dtype(self.dtype())); + + AT_DISPATCH_FLOATING_TYPES(self.scalar_type(), "gather_uint32", [&] { + gather_uint32( + static_cast(self.numel()), + static_cast(index.numel()), + reinterpret_cast(index.data_ptr()), + self.data_ptr(), + result.data_ptr()); + }); + + return result; +} + +void py_scatter_ema_uint32(const torch::Tensor &self, + const uint32_t dim, + const torch::Tensor &index, + const double decay, + const torch::Tensor &values) { + TORCH_CHECK(dim == 0, "dim must be 0"); + TORCH_CHECK(self.is_floating_point(), "self must be a tensor of a floating-point type"); + TORCH_CHECK(self.is_contiguous(), "self must be contiguous"); + TORCH_CHECK(self.dim() == 1, "self must be 1-dimensional"); + TORCH_CHECK(self.is_cuda(), "self must be on CUDA"); + + TORCH_CHECK(index.dtype() == torch::kInt32, "index must be a tensor of type int32"); + TORCH_CHECK(index.is_contiguous(), "index must be contiguous"); + TORCH_CHECK(index.is_cuda(), "index must be on CUDA"); + + TORCH_CHECK(values.is_contiguous(), "values must be contiguous"); + + TORCH_CHECK(self.device() == index.device(), "self and index must be on the same device"); + TORCH_CHECK(values.device() == index.device(), "values and index must be on the same device"); + TORCH_CHECK(values.dtype() == self.dtype(), "values and self must have the same dtype"); + TORCH_CHECK(index.dim() == self.dim(), "self and index must have the same number of dimensions"); + TORCH_CHECK(values.sizes() == index.sizes(), "values and index must have the same shape"); + + AT_DISPATCH_FLOATING_TYPES(self.scalar_type(), "scatter_ema_uint32", [&] { + scatter_ema_uint32( + static_cast(self.numel()), + static_cast(index.numel()), + reinterpret_cast(index.data_ptr()), + decay, + values.data_ptr(), + self.data_ptr()); + }); +} + +PYBIND11_MODULE(tetranerf_cpp_extension, m) { + py::class_(m, "TetrahedraTracer") + .def(py::init()) + .def_property_readonly("device", &PyTetrahedraTracer::get_device) + .def("trace_rays", &PyTetrahedraTracer::trace_rays) + .def("trace_rays_triangles", &PyTetrahedraTracer::trace_rays_triangles) + .def("find_visited_cells", &PyTetrahedraTracer::find_visited_cells) + .def("find_tetrahedra", &PyTetrahedraTracer::find_tetrahedra) + .def("load_tetrahedra", &PyTetrahedraTracer::load_tetrahedra); + + m.def("triangulate", &py_triangulate); + m.def("find_average_spacing", &py_find_average_spacing); + m.def("interpolate_values", &py_interpolate_values); + m.def("interpolate_values_backward", &py_interpolate_values_backward); + m.def("gather_uint32", &py_gather_uint32); + m.def("scatter_ema_uint32", &py_scatter_ema_uint32); +} \ No newline at end of file diff --git a/Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.cpp b/Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.cpp new file mode 100644 index 0000000000..5e8caea4f6 --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.cpp @@ -0,0 +1,926 @@ +#include "tetrahedra_tracer.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "optix_types.h" +#include "utils/exception.h" +#include "utils/tensor.h" +#include "utils/vec_math.h" + +namespace fs = std::filesystem; + +namespace { + +template +struct SbtRecord { + __align__(OPTIX_SBT_RECORD_ALIGNMENT) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +using RayGenSbtRecord = SbtRecord; +using MissSbtRecord = SbtRecord; +using HitGroupSbtRecord = SbtRecord; + +uint3 order_faces(const uint3 &face) { + uint3 ordered_face = face; + if (ordered_face.x > ordered_face.y) std::swap(ordered_face.x, ordered_face.y); + if (ordered_face.y > ordered_face.z) std::swap(ordered_face.y, ordered_face.z); + if (ordered_face.x > ordered_face.y) std::swap(ordered_face.x, ordered_face.y); + return ordered_face; +} + +static void context_log_cb(unsigned int level, const char *tag, const char *message, void *) { + std::cerr << "[" << std::setw(2) << level << "][" << std::setw(12) << tag << "]: " << message << "\n"; +} + +void create_module_from_embedded( + const OptixDeviceContext &context, + const std::string &input, + const OptixModuleCompileOptions &module_compile_options, + const OptixPipelineCompileOptions &pipeline_compile_options, + OptixModule *module) { + char log[2048] = {}; + size_t sizeof_log = sizeof(log); + +#if (OPTIX_ABI_VERSION > 54) + OPTIX_CHECK(optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + input.c_str(), + input.size(), + log, + &sizeof_log, + module)); +#else + OPTIX_CHECK(optixModuleCreateFromPTX( + context, + &module_compile_options, + &pipeline_compile_options, + input.c_str(), + input.size(), + log, + &sizeof_log, + module)); +#endif +} + +OptixStackSizes collect_stack_sizes(const std::vector &program_groups, OptixPipeline pipeline) { + OptixStackSizes out = {}; + for (auto pg : program_groups) { + OptixStackSizes ss = {}; +#if (OPTIX_ABI_VERSION >= 55) + OPTIX_CHECK(optixProgramGroupGetStackSize(pg, &ss, pipeline)); +#else + OPTIX_CHECK(optixProgramGroupGetStackSize(pg, &ss)); +#endif + out.cssRG = std::max(out.cssRG, ss.cssRG); + out.cssMS = std::max(out.cssMS, ss.cssMS); + out.cssCH = std::max(out.cssCH, ss.cssCH); + out.cssAH = std::max(out.cssAH, ss.cssAH); + out.cssIS = std::max(out.cssIS, ss.cssIS); + out.cssCC = std::max(out.cssCC, ss.cssCC); + out.dssDC = std::max(out.dssDC, ss.dssDC); + } + return out; +} + +void configure_pipeline_stack(OptixPipeline pipeline, const std::vector &program_groups, uint32_t max_trace_depth) { + OptixStackSizes stack_sizes = collect_stack_sizes(program_groups, pipeline); + + uint32_t direct_callable_stack_size_from_traversal = 0; + uint32_t direct_callable_stack_size_from_state = 0; + uint32_t continuation_stack_size = 0; + + OPTIX_CHECK(optixUtilComputeStackSizes( + &stack_sizes, + max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDepth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, + &continuation_stack_size)); + + OPTIX_CHECK(optixPipelineSetStackSize( + pipeline, + direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, + continuation_stack_size, + 1)); +} + +void destroy_sbt_records(OptixShaderBindingTable &sbt) { + if (sbt.raygenRecord) { + CUDA_CHECK(cudaFree(reinterpret_cast(sbt.raygenRecord))); + } + if (sbt.missRecordBase) { + CUDA_CHECK(cudaFree(reinterpret_cast(sbt.missRecordBase))); + } + if (sbt.hitgroupRecordBase) { + CUDA_CHECK(cudaFree(reinterpret_cast(sbt.hitgroupRecordBase))); + } + if (sbt.callablesRecordBase) { + CUDA_CHECK(cudaFree(reinterpret_cast(sbt.callablesRecordBase))); + } + if (sbt.exceptionRecord) { + CUDA_CHECK(cudaFree(reinterpret_cast(sbt.exceptionRecord))); + } + sbt = {}; +} + +void build_basic_sbt( + OptixProgramGroup raygen_prog_group, + OptixProgramGroup miss_prog_group, + OptixProgramGroup hitgroup_prog_group, + OptixShaderBindingTable *sbt) { + CUdeviceptr raygen_record = 0; + CUdeviceptr miss_record = 0; + CUdeviceptr hitgroup_record = 0; + + const size_t raygen_record_size = sizeof(RayGenSbtRecord); + const size_t miss_record_size = sizeof(MissSbtRecord); + const size_t hitgroup_record_size = sizeof(HitGroupSbtRecord); + + CUDA_CHECK(cudaMalloc(reinterpret_cast(&raygen_record), raygen_record_size)); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&miss_record), miss_record_size)); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&hitgroup_record), hitgroup_record_size)); + + RayGenSbtRecord rg_sbt = {}; + MissSbtRecord ms_sbt = {}; + HitGroupSbtRecord hg_sbt = {}; + + OPTIX_CHECK(optixSbtRecordPackHeader(raygen_prog_group, &rg_sbt)); + OPTIX_CHECK(optixSbtRecordPackHeader(miss_prog_group, &ms_sbt)); + OPTIX_CHECK(optixSbtRecordPackHeader(hitgroup_prog_group, &hg_sbt)); + + CUDA_CHECK(cudaMemcpy(reinterpret_cast(raygen_record), &rg_sbt, raygen_record_size, cudaMemcpyHostToDevice)); + CUDA_CHECK(cudaMemcpy(reinterpret_cast(miss_record), &ms_sbt, miss_record_size, cudaMemcpyHostToDevice)); + CUDA_CHECK(cudaMemcpy(reinterpret_cast(hitgroup_record), &hg_sbt, hitgroup_record_size, cudaMemcpyHostToDevice)); + + sbt->raygenRecord = raygen_record; + sbt->missRecordBase = miss_record; + sbt->missRecordStrideInBytes = sizeof(MissSbtRecord); + sbt->missRecordCount = 1; + sbt->hitgroupRecordBase = hitgroup_record; + sbt->hitgroupRecordStrideInBytes = sizeof(HitGroupSbtRecord); + sbt->hitgroupRecordCount = 1; +} + +} // namespace + +template <> +struct std::hash { + std::size_t operator()(const uint3 &k) const { + using std::hash; + return ((hash()(k.x) ^ (hash()(k.y) << 1)) >> 1) ^ (hash()(k.z) << 1); + } +}; + +void convert_tetrahedra_to_triangles( + const size_t num_tetrahedra, + const uint4 *tetrahedra, + std::vector &triangles, + std::vector &triangles_tetrahedra) { + unsigned int empty = ~((unsigned int)0); + std::unordered_map known_faces; + + for (size_t i = 0; i < num_tetrahedra; ++i) { + for (int j = 0; j < 4; ++j) { + uint4 tetrahedron = tetrahedra[i]; + uint3 triangle = make_uint3( + ((unsigned int *)&tetrahedron)[(j + 1) % 4], + ((unsigned int *)&tetrahedron)[(j + 2) % 4], + ((unsigned int *)&tetrahedron)[(j + 3) % 4]); + auto ordered_triangle = order_faces(triangle); + + if (known_faces.find(ordered_triangle) == known_faces.end()) { + known_faces[ordered_triangle] = static_cast(triangles_tetrahedra.size()); + triangles.push_back(triangle); + triangles_tetrahedra.push_back(make_uint2(static_cast(i), empty)); + } else { + if (triangles_tetrahedra[known_faces[ordered_triangle]].y != empty) { + throw std::runtime_error("A triangle is shared by more than two tetrahedra!"); + } + triangles_tetrahedra[known_faces[ordered_triangle]].y = static_cast(i); + } + } + } +} + +TetrahedraTracer::TetrahedraTracer(int8_t device) : device(device) { + context = nullptr; + CUDA_CHECK(cudaSetDevice(device)); + + { + CUDA_CHECK(cudaFree(0)); + OPTIX_CHECK(optixInit()); + + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + + CUcontext cuCtx = 0; + OPTIX_CHECK(optixDeviceContextCreate(cuCtx, &options, &context)); + } + + tetrahedra_structure = std::move(TetrahedraStructure(context, device)); + trace_rays_pipeline = std::move(TraceRaysPipeline(context, device)); + trace_rays_triangles_pipeline = std::move(TraceRaysTrianglesPipeline(context, device)); + find_tetrahedra_pipeline = std::move(FindTetrahedraPipeline(context, device)); +} + +TetrahedraTracer::TetrahedraTracer(TetrahedraTracer &&other) noexcept + : device(std::exchange(other.device, -1)), + context(std::exchange(other.context, nullptr)), + tetrahedra_structure(std::move(other.tetrahedra_structure)), + trace_rays_pipeline(std::move(other.trace_rays_pipeline)), + trace_rays_triangles_pipeline(std::move(other.trace_rays_triangles_pipeline)), + find_tetrahedra_pipeline(std::move(other.find_tetrahedra_pipeline)) {} + +TetrahedraTracer::~TetrahedraTracer() noexcept(false) { + auto moved_structure = std::move(tetrahedra_structure); + auto moved_trace = std::move(trace_rays_pipeline); + auto moved_trace_tri = std::move(trace_rays_triangles_pipeline); + auto moved_find = std::move(find_tetrahedra_pipeline); + (void)moved_structure; + (void)moved_trace; + (void)moved_trace_tri; + (void)moved_find; + + if (context != nullptr && device != -1) { + CUDA_CHECK(cudaSetDevice(device)); + OPTIX_CHECK(optixDeviceContextDestroy(std::exchange(context, nullptr))); + } +} + +TetrahedraStructure::TetrahedraStructure() noexcept + : device(-1), + context(nullptr), + num_vertices(0), + num_cells(0), + gas_handle_(0), + d_gas_output_buffer(0), + tetrahedra_vertices(nullptr), + triangle_indices_(nullptr), + triangle_tetrahedra_(nullptr) {} + +TetrahedraStructure::TetrahedraStructure(TetrahedraStructure &&other) noexcept + : context(std::exchange(other.context, nullptr)), + device(std::exchange(other.device, -1)), + num_vertices(std::exchange(other.num_vertices, 0)), + num_cells(std::exchange(other.num_cells, 0)), + gas_handle_(std::exchange(other.gas_handle_, 0)), + d_gas_output_buffer(std::exchange(other.d_gas_output_buffer, 0)), + tetrahedra_vertices(std::exchange(other.tetrahedra_vertices, nullptr)), + triangle_indices_(std::exchange(other.triangle_indices_, nullptr)), + triangle_tetrahedra_(std::exchange(other.triangle_tetrahedra_, nullptr)) {} + +void TetrahedraStructure::release() { + bool device_set = false; + + if (d_gas_output_buffer != 0) { + if (!device_set) { + CUDA_CHECK(cudaSetDevice(device)); + device_set = true; + } + CUDA_CHECK(cudaFree(reinterpret_cast(d_gas_output_buffer))); + d_gas_output_buffer = 0; + } + + gas_handle_ = 0; + tetrahedra_vertices = nullptr; + + if (triangle_indices_ != nullptr) { + if (!device_set) { + CUDA_CHECK(cudaSetDevice(device)); + device_set = true; + } + CUDA_CHECK(cudaFree(reinterpret_cast(triangle_indices_))); + triangle_indices_ = nullptr; + } + + if (triangle_tetrahedra_ != nullptr) { + if (!device_set) { + CUDA_CHECK(cudaSetDevice(device)); + device_set = true; + } + CUDA_CHECK(cudaFree(reinterpret_cast(triangle_tetrahedra_))); + triangle_tetrahedra_ = nullptr; + } +} + +TetrahedraStructure::~TetrahedraStructure() noexcept(false) { + if (device != -1) { + release(); + } + device = -1; + context = nullptr; +} + +void TetrahedraStructure::build( + const size_t num_vertices, + const size_t num_cells, + const float3 *d_vertices, + const uint4 *cells) { + release(); + CUDA_CHECK(cudaSetDevice(device)); + + unsigned int num_triangles = 0; + { + auto *h_cells = new uint4[num_cells]; + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(h_cells), + cells, + num_cells * sizeof(uint4), + cudaMemcpyDeviceToHost)); + + std::vector h_triangle_indices; + std::vector h_triangle_tetrahedra; + convert_tetrahedra_to_triangles(num_cells, h_cells, h_triangle_indices, h_triangle_tetrahedra); + delete[] h_cells; + + CUDA_CHECK(cudaMalloc(reinterpret_cast(&triangle_tetrahedra_), h_triangle_tetrahedra.size() * sizeof(uint2))); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(triangle_tetrahedra_), + h_triangle_tetrahedra.data(), + h_triangle_tetrahedra.size() * sizeof(uint2), + cudaMemcpyHostToDevice)); + + CUDA_CHECK(cudaMalloc(reinterpret_cast(&triangle_indices_), h_triangle_indices.size() * sizeof(uint3))); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(triangle_indices_), + h_triangle_indices.data(), + h_triangle_indices.size() * sizeof(uint3), + cudaMemcpyHostToDevice)); + + num_triangles = static_cast(h_triangle_indices.size()); + } + + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_NONE; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + const uint32_t triangle_input_flags[1] = {OPTIX_GEOMETRY_FLAG_NONE}; + + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.vertexBuffers = reinterpret_cast(&d_vertices); + triangle_input.triangleArray.numVertices = static_cast(num_vertices); + triangle_input.triangleArray.indexFormat = OPTIX_INDICES_FORMAT_UNSIGNED_INT3; + triangle_input.triangleArray.indexBuffer = reinterpret_cast(triangle_indices_); + triangle_input.triangleArray.numIndexTriplets = num_triangles; + triangle_input.triangleArray.flags = triangle_input_flags; + triangle_input.triangleArray.numSbtRecords = 1; + + OptixAccelBufferSizes gas_buffer_sizes = {}; + OPTIX_CHECK(optixAccelComputeMemoryUsage(context, &accel_options, &triangle_input, 1, &gas_buffer_sizes)); + + CUdeviceptr d_temp_buffer_gas = 0; + CUDA_CHECK(cudaMalloc(reinterpret_cast(&d_temp_buffer_gas), gas_buffer_sizes.tempSizeInBytes)); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&d_gas_output_buffer), gas_buffer_sizes.outputSizeInBytes)); + + OPTIX_CHECK(optixAccelBuild( + context, + 0, + &accel_options, + &triangle_input, + 1, + d_temp_buffer_gas, + gas_buffer_sizes.tempSizeInBytes, + d_gas_output_buffer, + gas_buffer_sizes.outputSizeInBytes, + &gas_handle_, + nullptr, + 0)); + + this->num_vertices = num_vertices; + this->num_cells = num_cells; + this->tetrahedra_vertices = d_vertices; + + CUDA_CHECK(cudaFree(reinterpret_cast(d_temp_buffer_gas))); +} + +TraceRaysPipeline::TraceRaysPipeline(const OptixDeviceContext &context, int8_t device) + : context(context), device(device) { + CUDA_CHECK(cudaSetDevice(device)); + + OptixModuleCompileOptions module_compile_options = {}; + module_compile_options.maxRegisterCount = OPTIX_COMPILE_DEFAULT_MAX_REGISTER_COUNT; + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT; +#if (OPTIX_ABI_VERSION > 54) + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL; +#else + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO; +#endif + + OptixPipelineCompileOptions pipeline_compile_options = {}; + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 1; + pipeline_compile_options.numAttributeValues = 2; +#ifdef DEBUG + pipeline_compile_options.exceptionFlags = + OPTIX_EXCEPTION_FLAG_DEBUG | OPTIX_EXCEPTION_FLAG_TRACE_DEPTH | OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; +#else + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; +#endif + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; + + const std::string input = load_ptx_data(); + create_module_from_embedded(context, input, module_compile_options, pipeline_compile_options, &module); + + { + OptixProgramGroupOptions program_group_options = {}; + + OptixProgramGroupDesc raygen_desc = {}; + raygen_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_desc.raygen.module = module; + raygen_desc.raygen.entryFunctionName = "__raygen__rg"; + + OptixProgramGroupDesc miss_desc = {}; + miss_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_desc.miss.module = module; + miss_desc.miss.entryFunctionName = "__miss__ms"; + + OptixProgramGroupDesc hitgroup_desc = {}; + hitgroup_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_desc.hitgroup.moduleCH = module; + hitgroup_desc.hitgroup.moduleAH = module; + hitgroup_desc.hitgroup.entryFunctionNameCH = "__closesthit__ms"; + hitgroup_desc.hitgroup.entryFunctionNameAH = "__anyhit__ms"; + + char log[2048] = {}; + size_t sizeof_log = sizeof(log); + + OPTIX_CHECK_LOG(optixProgramGroupCreate(context, &raygen_desc, 1, &program_group_options, log, &sizeof_log, &raygen_prog_group)); + + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate(context, &miss_desc, 1, &program_group_options, log, &sizeof_log, &miss_prog_group)); + + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate(context, &hitgroup_desc, 1, &program_group_options, log, &sizeof_log, &hitgroup_prog_group)); + } + + { + const uint32_t max_trace_depth = 2; + std::vector program_groups = {raygen_prog_group, miss_prog_group, hitgroup_prog_group}; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; +#if (OPTIX_ABI_VERSION <= 54) + pipeline_link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + char log[2048] = {}; + size_t sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups.data(), + static_cast(program_groups.size()), + log, + &sizeof_log, + &pipeline)); + + configure_pipeline_stack(pipeline, program_groups, max_trace_depth); + } + + build_basic_sbt(raygen_prog_group, miss_prog_group, hitgroup_prog_group, &sbt); + + CUDA_CHECK(cudaStreamCreate(&stream)); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&d_param), sizeof(Params))); +} + +TraceRaysPipeline::TraceRaysPipeline(TraceRaysPipeline &&other) noexcept + : context(std::exchange(other.context, nullptr)), + device(std::exchange(other.device, -1)), + module(std::exchange(other.module, nullptr)), + sbt(std::exchange(other.sbt, {})), + pipeline(std::exchange(other.pipeline, nullptr)), + d_param(std::exchange(other.d_param, 0)), + stream(std::exchange(other.stream, nullptr)), + raygen_prog_group(std::exchange(other.raygen_prog_group, nullptr)), + miss_prog_group(std::exchange(other.miss_prog_group, nullptr)), + hitgroup_prog_group(std::exchange(other.hitgroup_prog_group, nullptr)), + eps(std::exchange(other.eps, 1e-6f)) {} + +TraceRaysPipeline::~TraceRaysPipeline() noexcept(false) { + const auto current_device = std::exchange(device, -1); + if (current_device == -1) { + return; + } + + CUDA_CHECK(cudaSetDevice(current_device)); + + if (d_param != 0) { + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(d_param, 0)))); + } + + destroy_sbt_records(sbt); + + if (stream != nullptr) { + CUDA_CHECK(cudaStreamDestroy(std::exchange(stream, nullptr))); + } + if (pipeline != nullptr) { + OPTIX_CHECK(optixPipelineDestroy(std::exchange(pipeline, nullptr))); + } + if (raygen_prog_group != nullptr) { + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(raygen_prog_group, nullptr))); + } + if (miss_prog_group != nullptr) { + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(miss_prog_group, nullptr))); + } + if (hitgroup_prog_group != nullptr) { + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(hitgroup_prog_group, nullptr))); + } + if (module != nullptr) { + OPTIX_CHECK(optixModuleDestroy(std::exchange(module, nullptr))); + } + + context = nullptr; +} + +void TraceRaysPipeline::trace_rays( + const TetrahedraStructure *tetrahedra_structure, + const size_t num_rays, + const unsigned int max_ray_triangles, + const float3 *ray_origins, + const float3 *ray_directions, + unsigned int *num_visited_cells_out, + unsigned int *visited_cells_out, + float3 *barycentric_coordinates_out, + float2 *hit_distances_out, + uint4 *vertex_indices_out) { + CUDA_CHECK(cudaSetDevice(device)); + + Params params = {}; + params.triangle_tetrahedra = tetrahedra_structure->triangle_tetrahedra(); + params.triangle_indices = tetrahedra_structure->triangle_indices(); + params.num_visited_tetrahedra = num_visited_cells_out; + params.visited_tetrahedra = visited_cells_out; + params.vertex_indices = vertex_indices_out; + params.max_ray_triangles = max_ray_triangles; + params.barycentric_coordinates = barycentric_coordinates_out; + params.hit_distances = hit_distances_out; + params.handle = tetrahedra_structure->gas_handle(); + params.ray_origins = ray_origins; + params.ray_directions = ray_directions; + + CUDA_CHECK(cudaMemcpy(reinterpret_cast(d_param), ¶ms, sizeof(params), cudaMemcpyHostToDevice)); + OPTIX_CHECK(optixLaunch(pipeline, stream, d_param, sizeof(params), &sbt, static_cast(num_rays), 1, 1)); + CUDA_SYNC_CHECK(); + CUDA_CHECK(cudaStreamSynchronize(stream)); +} + +FindTetrahedraPipeline::FindTetrahedraPipeline(const OptixDeviceContext &context, int8_t device) + : context(context), device(device) { + CUDA_CHECK(cudaSetDevice(device)); + + OptixModuleCompileOptions module_compile_options = {}; + module_compile_options.maxRegisterCount = OPTIX_COMPILE_DEFAULT_MAX_REGISTER_COUNT; + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT; +#if (OPTIX_ABI_VERSION > 54) + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL; +#else + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO; +#endif + + OptixPipelineCompileOptions pipeline_compile_options = {}; + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 4; + pipeline_compile_options.numAttributeValues = 2; +#ifdef DEBUG + pipeline_compile_options.exceptionFlags = + OPTIX_EXCEPTION_FLAG_DEBUG | OPTIX_EXCEPTION_FLAG_TRACE_DEPTH | OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; +#else + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; +#endif + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; + + const std::string input = load_ptx_data(); + create_module_from_embedded(context, input, module_compile_options, pipeline_compile_options, &module); + + { + OptixProgramGroupOptions program_group_options = {}; + + OptixProgramGroupDesc raygen_desc = {}; + raygen_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_desc.raygen.module = module; + raygen_desc.raygen.entryFunctionName = "__raygen__ft"; + + OptixProgramGroupDesc miss_desc = {}; + miss_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_desc.miss.module = module; + miss_desc.miss.entryFunctionName = "__miss__ft"; + + OptixProgramGroupDesc hitgroup_desc = {}; + hitgroup_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_desc.hitgroup.moduleCH = module; + hitgroup_desc.hitgroup.entryFunctionNameCH = "__closesthit__ft"; + + char log[2048] = {}; + size_t sizeof_log = sizeof(log); + + OPTIX_CHECK_LOG(optixProgramGroupCreate(context, &raygen_desc, 1, &program_group_options, log, &sizeof_log, &raygen_prog_group)); + + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate(context, &miss_desc, 1, &program_group_options, log, &sizeof_log, &miss_prog_group)); + + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate(context, &hitgroup_desc, 1, &program_group_options, log, &sizeof_log, &hitgroup_prog_group)); + } + + { + const uint32_t max_trace_depth = 1; + std::vector program_groups = {raygen_prog_group, miss_prog_group, hitgroup_prog_group}; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; +#if (OPTIX_ABI_VERSION <= 54) + pipeline_link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + char log[2048] = {}; + size_t sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups.data(), + static_cast(program_groups.size()), + log, + &sizeof_log, + &pipeline)); + + configure_pipeline_stack(pipeline, program_groups, max_trace_depth); + } + + build_basic_sbt(raygen_prog_group, miss_prog_group, hitgroup_prog_group, &sbt); + + CUDA_CHECK(cudaStreamCreate(&stream)); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&d_param), sizeof(ParamsFindTetrahedra))); +} + +FindTetrahedraPipeline::FindTetrahedraPipeline(FindTetrahedraPipeline &&other) noexcept + : context(std::exchange(other.context, nullptr)), + device(std::exchange(other.device, -1)), + module(std::exchange(other.module, nullptr)), + sbt(std::exchange(other.sbt, {})), + pipeline(std::exchange(other.pipeline, nullptr)), + d_param(std::exchange(other.d_param, 0)), + stream(std::exchange(other.stream, nullptr)), + raygen_prog_group(std::exchange(other.raygen_prog_group, nullptr)), + miss_prog_group(std::exchange(other.miss_prog_group, nullptr)), + hitgroup_prog_group(std::exchange(other.hitgroup_prog_group, nullptr)), + eps(std::exchange(other.eps, 1e-6f)) {} + +FindTetrahedraPipeline::~FindTetrahedraPipeline() noexcept(false) { + const auto current_device = std::exchange(device, -1); + if (current_device == -1) { + return; + } + + CUDA_CHECK(cudaSetDevice(current_device)); + + if (d_param != 0) { + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(d_param, 0)))); + } + + destroy_sbt_records(sbt); + + if (stream != nullptr) { + CUDA_CHECK(cudaStreamDestroy(std::exchange(stream, nullptr))); + } + if (pipeline != nullptr) { + OPTIX_CHECK(optixPipelineDestroy(std::exchange(pipeline, nullptr))); + } + if (raygen_prog_group != nullptr) { + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(raygen_prog_group, nullptr))); + } + if (miss_prog_group != nullptr) { + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(miss_prog_group, nullptr))); + } + if (hitgroup_prog_group != nullptr) { + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(hitgroup_prog_group, nullptr))); + } + if (module != nullptr) { + OPTIX_CHECK(optixModuleDestroy(std::exchange(module, nullptr))); + } + + context = nullptr; +} + +void FindTetrahedraPipeline::find_tetrahedra( + const TetrahedraStructure *tetrahedra_structure, + const size_t num_points, + const float3 *points, + unsigned int *tetrahedra_out, + float3 *barycentric_coordinates_out, + uint4 *vertex_indices_out) { + CUDA_CHECK(cudaSetDevice(device)); + + ParamsFindTetrahedra params = {}; + params.barycentric_coordinates = barycentric_coordinates_out; + params.ray_origins = points; + params.tetrahedra = tetrahedra_out; + params.vertex_indices = vertex_indices_out; + params.triangle_indices = tetrahedra_structure->triangle_indices(); + params.triangle_tetrahedra = tetrahedra_structure->triangle_tetrahedra(); + params.handle = tetrahedra_structure->gas_handle(); + + CUDA_CHECK(cudaMemcpy(reinterpret_cast(d_param), ¶ms, sizeof(params), cudaMemcpyHostToDevice)); + OPTIX_CHECK(optixLaunch(pipeline, stream, d_param, sizeof(params), &sbt, static_cast(num_points), 1, 1)); + CUDA_SYNC_CHECK(); + CUDA_CHECK(cudaStreamSynchronize(stream)); +} + +TraceRaysTrianglesPipeline::TraceRaysTrianglesPipeline(const OptixDeviceContext &context, int8_t device) + : context(context), device(device) { + CUDA_CHECK(cudaSetDevice(device)); + + OptixModuleCompileOptions module_compile_options = {}; + module_compile_options.maxRegisterCount = OPTIX_COMPILE_DEFAULT_MAX_REGISTER_COUNT; + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT; +#if (OPTIX_ABI_VERSION > 54) + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL; +#else + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO; +#endif + + OptixPipelineCompileOptions pipeline_compile_options = {}; + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 1; + pipeline_compile_options.numAttributeValues = 2; +#ifdef DEBUG + pipeline_compile_options.exceptionFlags = + OPTIX_EXCEPTION_FLAG_DEBUG | OPTIX_EXCEPTION_FLAG_TRACE_DEPTH | OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; +#else + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; +#endif + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; + + const std::string input = load_ptx_data(); + create_module_from_embedded(context, input, module_compile_options, pipeline_compile_options, &module); + + { + OptixProgramGroupOptions program_group_options = {}; + + OptixProgramGroupDesc raygen_desc = {}; + raygen_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_desc.raygen.module = module; + raygen_desc.raygen.entryFunctionName = "__raygen__rg"; + + OptixProgramGroupDesc miss_desc = {}; + miss_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_desc.miss.module = module; + miss_desc.miss.entryFunctionName = "__miss__ms"; + + OptixProgramGroupDesc hitgroup_desc = {}; + hitgroup_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_desc.hitgroup.moduleCH = module; + hitgroup_desc.hitgroup.moduleAH = module; + hitgroup_desc.hitgroup.entryFunctionNameCH = "__closesthit__ms"; + hitgroup_desc.hitgroup.entryFunctionNameAH = "__anyhit__ms"; + + char log[2048] = {}; + size_t sizeof_log = sizeof(log); + + OPTIX_CHECK_LOG(optixProgramGroupCreate(context, &raygen_desc, 1, &program_group_options, log, &sizeof_log, &raygen_prog_group)); + + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate(context, &miss_desc, 1, &program_group_options, log, &sizeof_log, &miss_prog_group)); + + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate(context, &hitgroup_desc, 1, &program_group_options, log, &sizeof_log, &hitgroup_prog_group)); + } + + { + const uint32_t max_trace_depth = 2; + std::vector program_groups = {raygen_prog_group, miss_prog_group, hitgroup_prog_group}; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; +#if (OPTIX_ABI_VERSION <= 54) + pipeline_link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; +#endif + + char log[2048] = {}; + size_t sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups.data(), + static_cast(program_groups.size()), + log, + &sizeof_log, + &pipeline)); + + configure_pipeline_stack(pipeline, program_groups, max_trace_depth); + } + + build_basic_sbt(raygen_prog_group, miss_prog_group, hitgroup_prog_group, &sbt); + + CUDA_CHECK(cudaStreamCreate(&stream)); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&d_param), sizeof(ParamsTraceRaysTriangles))); +} + +TraceRaysTrianglesPipeline::TraceRaysTrianglesPipeline(TraceRaysTrianglesPipeline &&other) noexcept + : context(std::exchange(other.context, nullptr)), + device(std::exchange(other.device, -1)), + module(std::exchange(other.module, nullptr)), + sbt(std::exchange(other.sbt, {})), + pipeline(std::exchange(other.pipeline, nullptr)), + d_param(std::exchange(other.d_param, 0)), + stream(std::exchange(other.stream, nullptr)), + raygen_prog_group(std::exchange(other.raygen_prog_group, nullptr)), + miss_prog_group(std::exchange(other.miss_prog_group, nullptr)), + hitgroup_prog_group(std::exchange(other.hitgroup_prog_group, nullptr)) {} + +TraceRaysTrianglesPipeline::~TraceRaysTrianglesPipeline() noexcept(false) { + const auto current_device = std::exchange(device, -1); + if (current_device == -1) { + return; + } + + CUDA_CHECK(cudaSetDevice(current_device)); + + if (d_param != 0) { + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(d_param, 0)))); + } + + destroy_sbt_records(sbt); + + if (stream != nullptr) { + CUDA_CHECK(cudaStreamDestroy(std::exchange(stream, nullptr))); + } + if (pipeline != nullptr) { + OPTIX_CHECK(optixPipelineDestroy(std::exchange(pipeline, nullptr))); + } + if (raygen_prog_group != nullptr) { + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(raygen_prog_group, nullptr))); + } + if (miss_prog_group != nullptr) { + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(miss_prog_group, nullptr))); + } + if (hitgroup_prog_group != nullptr) { + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(hitgroup_prog_group, nullptr))); + } + if (module != nullptr) { + OPTIX_CHECK(optixModuleDestroy(std::exchange(module, nullptr))); + } + + context = nullptr; +} + +void TraceRaysTrianglesPipeline::trace_rays( + const TetrahedraStructure *tetrahedra_structure, + const size_t num_rays, + const unsigned int max_ray_triangles, + const float3 *ray_origins, + const float3 *ray_directions, + unsigned int *num_visited_triangles_out, + unsigned int *visited_triangles_out, + float2 *barycentric_coordinates_out, + float *hit_distances_out, + uint3 *vertex_indices_out) { + CUDA_CHECK(cudaSetDevice(device)); + + ParamsTraceRaysTriangles params = {}; + params.triangle_tetrahedra = tetrahedra_structure->triangle_tetrahedra(); + params.triangle_indices = tetrahedra_structure->triangle_indices(); + params.num_visited_triangles = num_visited_triangles_out; + params.visited_triangles = visited_triangles_out; + params.vertex_indices = vertex_indices_out; + params.max_ray_triangles = max_ray_triangles; + params.barycentric_coordinates = barycentric_coordinates_out; + params.hit_distances = hit_distances_out; + params.handle = tetrahedra_structure->gas_handle(); + params.ray_origins = ray_origins; + params.ray_directions = ray_directions; + + CUDA_CHECK(cudaMemcpy(reinterpret_cast(d_param), ¶ms, sizeof(params), cudaMemcpyHostToDevice)); + OPTIX_CHECK(optixLaunch(pipeline, stream, d_param, sizeof(params), &sbt, static_cast(num_rays), 1, 1)); + CUDA_SYNC_CHECK(); + CUDA_CHECK(cudaStreamSynchronize(stream)); +} \ No newline at end of file diff --git a/Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.cpp.patched b/Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.cpp.patched new file mode 100644 index 0000000000..f487d3c941 --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.cpp.patched @@ -0,0 +1,1172 @@ +#include "tetrahedra_tracer.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "optix_types.h" +#include "utils/exception.h" +#include "utils/tensor.h" +#include "utils/vec_math.h" + +namespace fs = std::filesystem; + +uint3 order_faces(const uint3 &face) { + uint3 ordered_face = face; + if (ordered_face.x > ordered_face.y) { + std::swap(ordered_face.x, ordered_face.y); + } + if (ordered_face.y > ordered_face.z) { + std::swap(ordered_face.y, ordered_face.z); + } + if (ordered_face.x > ordered_face.y) { + std::swap(ordered_face.x, ordered_face.y); + } + return ordered_face; +} + +template <> +struct std::hash { + std::size_t operator()(const uint3 &k) const { + using std::hash; + using std::size_t; + using std::string; + return ((hash()(k.x) ^ (hash()(k.y) << 1)) >> 1) ^ (hash()(k.z) << 1); + } +}; + +void convert_tetrahedra_to_triangles(const size_t num_tetrahedra, + const uint4 *tetrahedra, + std::vector &triangles, + std::vector &triangles_tetrahedra) { + unsigned int empty = ~((unsigned int)0); + std::unordered_map known_faces; + for (size_t i = 0; i < num_tetrahedra; ++i) { + for (int j = 0; j < 4; ++j) { + uint4 tetrahedron = tetrahedra[i]; + uint3 triangle = make_uint3( + ((unsigned int *)&tetrahedron)[(j + 1) % 4], + ((unsigned int *)&tetrahedron)[(j + 2) % 4], + ((unsigned int *)&tetrahedron)[(j + 3) % 4]); + auto ordered_triangle = order_faces(triangle); + if (known_faces.find(ordered_triangle) == known_faces.end()) { + known_faces[ordered_triangle] = triangles_tetrahedra.size(); + triangles.push_back(triangle); + triangles_tetrahedra.push_back(make_uint2(i, empty)); + } else { + if (triangles_tetrahedra[known_faces[ordered_triangle]].y != empty) { + throw std::runtime_error("A triangle is shared by more than two tetrahedra!"); + } + triangles_tetrahedra[known_faces[ordered_triangle]].y = i; + } + } + } +} + +// These structs represent the data blocks of our SBT records +template +struct SbtRecord { + __align__(OPTIX_SBT_RECORD_ALIGNMENT) char header[OPTIX_SBT_RECORD_HEADER_SIZE]; + T data; +}; + +typedef SbtRecord RayGenSbtRecord; +typedef SbtRecord MissSbtRecord; +typedef SbtRecord HitGroupSbtRecord; + +// TODO: move to python +static void context_log_cb(unsigned int level, const char *tag, const char *message, void * /*cbdata */) { + std::cerr << "[" << std::setw(2) << level << "][" << std::setw(12) << tag << "]: " + << message << "\n"; +} + +TetrahedraTracer::TetrahedraTracer(int8_t device) : device(device) { + // Initialize fields + context = nullptr; + + // Switch to active device + CUDA_CHECK(cudaSetDevice(device)); + + // Load PTX first to make sure it exists + + char log[2048]; // For error reporting from OptiX creation functions + + // + // Initialize CUDA and create OptiX context + // + { + // Initialize CUDA + // Warning: CUDA should have been already initialized at this point!! + CUDA_CHECK(cudaFree(0)); + + // Initialize the OptiX API, loading all API entry points + OPTIX_CHECK(optixInit()); + + // Specify context options + OptixDeviceContextOptions options = {}; + options.logCallbackFunction = &context_log_cb; + options.logCallbackLevel = 4; + + // Associate a CUDA context (and therefore a specific GPU) with this + // device context + CUcontext cuCtx = 0; // zero means take the current context + OPTIX_CHECK(optixDeviceContextCreate(cuCtx, &options, &context)); + } + + trace_rays_pipeline = std::move(TraceRaysPipeline(context, device)); + trace_rays_triangles_pipeline = std::move(TraceRaysTrianglesPipeline(context, device)); + find_tetrahedra_pipeline = std::move(FindTetrahedraPipeline(context, device)); + tetrahedra_structure = std::move(TetrahedraStructure(context, device)); +} + +TetrahedraTracer::TetrahedraTracer(TetrahedraTracer &&other) + : context(std::exchange(other.context, nullptr)), + device(std::exchange(other.device, -1)), + tetrahedra_structure(std::move(other.tetrahedra_structure)), + find_tetrahedra_pipeline(std::move(other.find_tetrahedra_pipeline)), + trace_rays_pipeline(std::move(other.trace_rays_pipeline)), + trace_rays_triangles_pipeline(std::move(other.trace_rays_triangles_pipeline)) {} + +void TraceRaysPipeline::trace_rays(const TetrahedraStructure *tetrahedra_structure, + const size_t num_rays, + const unsigned int max_ray_triangles, + const float3 *ray_origins, + const float3 *ray_directions, + unsigned int *num_visited_cells_out, + unsigned int *visited_cells_out, + float3 *barycentric_coordinates_out, + float2 *hit_distances_out, + uint4 *vertex_indices_out) { + CUDA_CHECK(cudaSetDevice(device)); + float2 *triangle_barycentric_coordinates; + unsigned int *shared_visited_triangles; + float *triangle_hit_distances; + + // TODO: we can reuse the triangle memory + // No need to allocate again here + { + Params params; + params.triangle_tetrahedra = tetrahedra_structure->triangle_tetrahedra(); + params.triangle_indices = tetrahedra_structure->triangle_indices(); + params.num_visited_tetrahedra = num_visited_cells_out; + params.visited_tetrahedra = visited_cells_out; + params.vertex_indices = vertex_indices_out; + params.max_ray_triangles = max_ray_triangles; + params.barycentric_coordinates = barycentric_coordinates_out; + params.hit_distances = hit_distances_out; + params.handle = tetrahedra_structure->gas_handle(); + params.ray_origins = ray_origins; + params.ray_directions = ray_directions; + + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(d_param), + ¶ms, sizeof(params), + cudaMemcpyHostToDevice)); + OPTIX_CHECK(optixLaunch(pipeline, stream, d_param, sizeof(params), &sbt, num_rays, 1, 1)); + CUDA_SYNC_CHECK(); + CUDA_CHECK(cudaStreamSynchronize(stream)); + } +} + +TetrahedraTracer::~TetrahedraTracer() noexcept(false) { + // We call the destructor manually here to ensure correct destruction order + tetrahedra_structure.~TetrahedraStructure(); + trace_rays_pipeline.~TraceRaysPipeline(); + trace_rays_triangles_pipeline.~TraceRaysTrianglesPipeline(); + find_tetrahedra_pipeline.~FindTetrahedraPipeline(); + + if (context != nullptr && device != -1) { + CUDA_CHECK(cudaSetDevice(device)); + OPTIX_CHECK(optixDeviceContextDestroy(std::exchange(context, nullptr))); + } +} + +TetrahedraStructure::TetrahedraStructure() noexcept + : device(-1), + context(nullptr), + gas_handle_(0), + d_gas_output_buffer(0), + num_vertices(0), + num_cells(0), + tetrahedra_vertices(nullptr), + triangle_indices_(nullptr), + triangle_tetrahedra_(nullptr) {} + + +TetrahedraStructure::TetrahedraStructure(TetrahedraStructure &&other) noexcept + : device(std::exchange(other.device, -1)), + context(std::exchange(other.context, nullptr)), + gas_handle_(std::exchange(other.gas_handle_, 0)), + d_gas_output_buffer(std::exchange(other.d_gas_output_buffer, 0)), + num_vertices(std::exchange(other.num_vertices, 0)), + num_cells(std::exchange(other.num_cells, 0)), + tetrahedra_vertices(std::exchange(other.tetrahedra_vertices, nullptr)), + triangle_indices_(std::exchange(other.triangle_indices_, nullptr)), + triangle_tetrahedra_(std::exchange(other.triangle_tetrahedra_, nullptr)) {} + +void TetrahedraStructure::release() { + bool device_set = false; + if (d_gas_output_buffer != 0) { + if (!device_set) { CUDA_CHECK(cudaSetDevice(device)); device_set = true; } + CUDA_CHECK(cudaFree(reinterpret_cast(d_gas_output_buffer))); + d_gas_output_buffer = 0; + } + gas_handle_ = 0; + + // NOTE: we do not own the vertices and cells arrays + tetrahedra_vertices = nullptr; + if (triangle_indices_ != nullptr) { + if (!device_set) { CUDA_CHECK(cudaSetDevice(device)); device_set = true; } + CUDA_CHECK(cudaFree(reinterpret_cast(triangle_indices_))); + triangle_indices_ = nullptr; + } + if (triangle_tetrahedra_ != nullptr) { + if (!device_set) { CUDA_CHECK(cudaSetDevice(device)); device_set = true; } + CUDA_CHECK(cudaFree(reinterpret_cast(triangle_tetrahedra_))); + triangle_tetrahedra_ = nullptr; + } +} + +TetrahedraStructure::~TetrahedraStructure() noexcept(false) { + if (this->device != -1) { + release(); + } + const auto device = std::exchange(this->device, -1); +} + +void TetrahedraStructure::build(const size_t num_vertices, + const size_t num_cells, + const float3 *d_vertices, + const uint4 *cells) { + release(); + + CUDA_CHECK(cudaSetDevice(device)); + + // Build list of triangles from tetrahedra + unsigned int num_triangles; + { + uint4 *h_cells = new uint4[num_cells]; + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(h_cells), + cells, num_cells * sizeof(uint4), + cudaMemcpyDeviceToHost)); + std::vector h_triangle_indices; + std::vector h_triangle_tetrahedra; + convert_tetrahedra_to_triangles(num_cells, h_cells, h_triangle_indices, h_triangle_tetrahedra); + delete[] h_cells; + CUDA_CHECK(cudaMalloc( + reinterpret_cast(&triangle_tetrahedra_), + h_triangle_tetrahedra.size() * sizeof(uint2))); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(triangle_tetrahedra_), + h_triangle_tetrahedra.data(), + h_triangle_tetrahedra.size() * sizeof(uint2), + cudaMemcpyHostToDevice)); + CUDA_CHECK(cudaMalloc( + reinterpret_cast(&triangle_indices_), + h_triangle_indices.size() * sizeof(uint3))); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(triangle_indices_), + h_triangle_indices.data(), + h_triangle_indices.size() * sizeof(uint3), + cudaMemcpyHostToDevice)); + num_triangles = h_triangle_indices.size(); + } + + // Use default options for simplicity. In a real use case we would want to + // enable compaction, etc + OptixAccelBuildOptions accel_options = {}; + accel_options.buildFlags = OPTIX_BUILD_FLAG_NONE; + accel_options.operation = OPTIX_BUILD_OPERATION_BUILD; + + // Our build input is a simple list of non-indexed triangle vertices + const uint32_t triangle_input_flags[1] = {OPTIX_GEOMETRY_FLAG_NONE}; + OptixBuildInput triangle_input = {}; + triangle_input.type = OPTIX_BUILD_INPUT_TYPE_TRIANGLES; + triangle_input.triangleArray.vertexFormat = OPTIX_VERTEX_FORMAT_FLOAT3; + triangle_input.triangleArray.vertexBuffers = reinterpret_cast(&d_vertices); + triangle_input.triangleArray.numVertices = static_cast(num_vertices); + + triangle_input.triangleArray.indexFormat = OptixIndicesFormat::OPTIX_INDICES_FORMAT_UNSIGNED_INT3; + triangle_input.triangleArray.indexBuffer = reinterpret_cast(triangle_indices_); + triangle_input.triangleArray.numIndexTriplets = num_triangles; + + triangle_input.triangleArray.flags = triangle_input_flags; + triangle_input.triangleArray.numSbtRecords = 1; + + OptixAccelBufferSizes gas_buffer_sizes; + OPTIX_CHECK(optixAccelComputeMemoryUsage( + context, + &accel_options, + &triangle_input, + 1, // Number of build inputs + &gas_buffer_sizes)); + CUdeviceptr d_temp_buffer_gas; + CUDA_CHECK(cudaMalloc( + reinterpret_cast(&d_temp_buffer_gas), + gas_buffer_sizes.tempSizeInBytes)); + CUDA_CHECK(cudaMalloc( + reinterpret_cast(&d_gas_output_buffer), + gas_buffer_sizes.outputSizeInBytes)); + + OPTIX_CHECK(optixAccelBuild( + context, + 0, // CUDA stream + &accel_options, + &triangle_input, + 1, // num build inputs + d_temp_buffer_gas, + gas_buffer_sizes.tempSizeInBytes, + d_gas_output_buffer, + gas_buffer_sizes.outputSizeInBytes, + &gas_handle_, + nullptr, // emitted property list + 0 // num emitted properties + )); + this->num_vertices = num_vertices; + this->num_cells = num_cells; + this->tetrahedra_vertices = d_vertices; + + // We can now free the scratch space buffer used during build and the vertex + // inputs, since they are not needed by our trivial shading method + CUDA_CHECK(cudaFree(reinterpret_cast(d_temp_buffer_gas))); +} + +TraceRaysPipeline::TraceRaysPipeline(const OptixDeviceContext &context, int8_t device) : device(device), context(context) { + // Initialize fields + OptixPipelineCompileOptions pipeline_compile_options = {}; + + // Switch to active device + CUDA_CHECK(cudaSetDevice(device)); + + // Load PTX first to make sure it exists + + char log[2048]; // For error reporting from OptiX creation functions + + // + // Create module + // + { + OptixModuleCompileOptions module_compile_options = {}; + module_compile_options.maxRegisterCount = OPTIX_COMPILE_DEFAULT_MAX_REGISTER_COUNT; + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT; + +// The following is not supported in Optix 7.2 +// #define XSTR(x) STR(x) +// #define STR(x) #x +// #pragma message "Optix ABI version is: " XSTR(OPTIX_ABI_VERSION) +#if (OPTIX_ABI_VERSION > 54) + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL; +#else + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO; +#endif + + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 1; + // https://forums.developer.nvidia.com/t/how-to-calculate-numattributevalues-of-optixpipelinecompileoptions/110833 + pipeline_compile_options.numAttributeValues = 2; +#ifdef DEBUG // Enables debug exceptions during optix launches. This may incur significant performance cost and should only be done during development. + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_DEBUG | OPTIX_EXCEPTION_FLAG_TRACE_DEPTH | OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; +#else + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; +#endif + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; + + std::string input = TraceRaysPipeline::load_ptx_data(); + size_t sizeof_log = sizeof(log); + + #if (OPTIX_ABI_VERSION > 54) + OPTIX_CHECK(optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + ptx.c_str(), + ptx.size(), + log, &log_size, + &module + )); + #else + OPTIX_CHECK(optixModuleCreateFromPTX( + context, + &module_compile_options, + &pipeline_compile_options, + ptx.c_str(), + ptx.size(), + log, &log_size, + &module + )); + #endif + // + // Create program groups + // + { + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; // + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + size_t sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate( + context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + log, + &sizeof_log, + &raygen_prog_group)); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate( + context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + log, + &sizeof_log, + &miss_prog_group)); + + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_prog_group_desc.hitgroup.moduleCH = module; + hitgroup_prog_group_desc.hitgroup.moduleAH = module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ms"; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameAH = "__anyhit__ms"; + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate( + context, + &hitgroup_prog_group_desc, + 1, // num program groups + &program_group_options, + log, + &sizeof_log, + &hitgroup_prog_group)); + } + + // + // Link pipeline + // + { + const uint32_t max_trace_depth = 1; + OptixProgramGroup program_groups[] = {raygen_prog_group, miss_prog_group, hitgroup_prog_group}; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 2; + #if (OPTIX_ABI_VERSION <= 54) + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 2; + #if (OPTIX_ABI_VERSION <= 54) + pipeline_link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; + #endif + #endif + size_t sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof(program_groups) / sizeof(program_groups[0]), + log, + &sizeof_log, + &pipeline)); + + OptixStackSizes stack_sizes = {}; + for (auto &prog_group : program_groups) { + OPTIX_CHECK(optixUtilAccumulateStackSizes(prog_group, &stack_sizes)); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK(optixUtilComputeStackSizes(&stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size)); + OPTIX_CHECK(optixPipelineSetStackSize(pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + )); + } + + // + // Set up shader binding table + // + { + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof(RayGenSbtRecord); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&raygen_record), raygen_record_size)); + RayGenSbtRecord rg_sbt; + OPTIX_CHECK(optixSbtRecordPackHeader(raygen_prog_group, &rg_sbt)); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(raygen_record), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice)); + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof(MissSbtRecord); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&miss_record), miss_record_size)); + MissSbtRecord ms_sbt; + OPTIX_CHECK(optixSbtRecordPackHeader(miss_prog_group, &ms_sbt)); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(miss_record), + &ms_sbt, + miss_record_size, + cudaMemcpyHostToDevice)); + + CUdeviceptr hitgroup_record; + size_t hitgroup_record_size = sizeof(HitGroupSbtRecord); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&hitgroup_record), hitgroup_record_size)); + HitGroupSbtRecord hg_sbt; + OPTIX_CHECK(optixSbtRecordPackHeader(hitgroup_prog_group, &hg_sbt)); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(hitgroup_record), + &hg_sbt, + hitgroup_record_size, + cudaMemcpyHostToDevice)); + + sbt.raygenRecord = raygen_record; + sbt.missRecordBase = miss_record; + sbt.missRecordStrideInBytes = sizeof(MissSbtRecord); + sbt.missRecordCount = 1; + sbt.hitgroupRecordBase = hitgroup_record; + sbt.hitgroupRecordStrideInBytes = sizeof(HitGroupSbtRecord); + sbt.hitgroupRecordCount = 1; + } + + { + CUDA_CHECK(cudaStreamCreate(&stream)); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&d_param), sizeof(Params))); + } +} + + +TraceRaysPipeline::TraceRaysPipeline(TraceRaysPipeline &&other) noexcept + : device(std::exchange(other.device, -1)), + context(std::exchange(other.context, nullptr)), + pipeline(std::exchange(other.pipeline, nullptr)), + raygen_prog_group(std::exchange(other.raygen_prog_group, nullptr)), + miss_prog_group(std::exchange(other.miss_prog_group, nullptr)), + hitgroup_prog_group(std::exchange(other.hitgroup_prog_group, nullptr)), + module(std::exchange(other.module, nullptr)), + sbt(std::exchange(other.sbt, {})), + stream(std::exchange(other.stream, nullptr)), + d_param(std::exchange(other.d_param, 0)) {} + + + +TraceRaysPipeline::~TraceRaysPipeline() noexcept(false) { + const auto device = std::exchange(this->device, -1); + if (device == -1) { + return; + } + CUDA_CHECK(cudaSetDevice(device)); + if (d_param != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(d_param, 0)))); + if (sbt.raygenRecord != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.raygenRecord, 0)))); + if (sbt.missRecordBase != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.missRecordBase, 0)))); + if (sbt.hitgroupRecordBase != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.hitgroupRecordBase, 0)))); + if (sbt.callablesRecordBase) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.callablesRecordBase, 0)))); + if (sbt.exceptionRecord) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.exceptionRecord, 0)))); + sbt = {}; + if (stream != nullptr) + CUDA_CHECK(cudaStreamDestroy(std::exchange(stream, nullptr))); + if (pipeline != nullptr) + OPTIX_CHECK(optixPipelineDestroy(std::exchange(pipeline, nullptr))); + if (raygen_prog_group != nullptr) + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(raygen_prog_group, nullptr))); + if (miss_prog_group != nullptr) + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(miss_prog_group, nullptr))); + if (hitgroup_prog_group != nullptr) + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(hitgroup_prog_group, nullptr))); + if (module != nullptr) + OPTIX_CHECK(optixModuleDestroy(std::exchange(module, nullptr))); +} + +FindTetrahedraPipeline::FindTetrahedraPipeline(const OptixDeviceContext &context, int8_t device) : device(device), context(context) { + // Initialize fields + OptixPipelineCompileOptions pipeline_compile_options = {}; + + // Switch to active device + CUDA_CHECK(cudaSetDevice(device)); + + char log[2048]; // For error reporting from OptiX creation functions + + // + // Create module + // + { + OptixModuleCompileOptions module_compile_options = {}; + module_compile_options.maxRegisterCount = OPTIX_COMPILE_DEFAULT_MAX_REGISTER_COUNT; + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT; + +// The following is not supported in Optix 7.2 +// #define XSTR(x) STR(x) +// #define STR(x) #x +// #pragma message "Optix ABI version is: " XSTR(OPTIX_ABI_VERSION) +#if (OPTIX_ABI_VERSION > 54) + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL; +#else + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO; +#endif + + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 4; + // https://forums.developer.nvidia.com/t/how-to-calculate-numattributevalues-of-optixpipelinecompileoptions/110833 + pipeline_compile_options.numAttributeValues = 2; +#ifdef DEBUG // Enables debug exceptions during optix launches. This may incur significant performance cost and should only be done during development. + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_DEBUG | OPTIX_EXCEPTION_FLAG_TRACE_DEPTH | OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; +#else + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; +#endif + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; + + std::string input = load_ptx_data(); + size_t sizeof_log = sizeof(log); + + #if (OPTIX_ABI_VERSION > 54) + OPTIX_CHECK(optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + ptx.c_str(), + ptx.size(), + log, &log_size, + &module + )); + #else + OPTIX_CHECK(optixModuleCreateFromPTX( + context, + &module_compile_options, + &pipeline_compile_options, + ptx.c_str(), + ptx.size(), + log, &log_size, + &module + )); + #endif + + // + // Create program groups + // + { + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; // + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__ft"; + size_t sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate( + context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + log, + &sizeof_log, + &raygen_prog_group)); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ft"; + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate( + context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + log, + &sizeof_log, + &miss_prog_group)); + + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_prog_group_desc.hitgroup.moduleCH = module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ft"; + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate( + context, + &hitgroup_prog_group_desc, + 1, // num program groups + &program_group_options, + log, + &sizeof_log, + &hitgroup_prog_group)); + } + + // + // Link pipeline + // + { + const uint32_t max_trace_depth = 1; + OptixProgramGroup program_groups[] = {raygen_prog_group, miss_prog_group, hitgroup_prog_group}; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + pipeline_link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; + size_t sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof(program_groups) / sizeof(program_groups[0]), + log, + &sizeof_log, + &pipeline)); + + OptixStackSizes stack_sizes = {}; + for (auto &prog_group : program_groups) { + OPTIX_CHECK(optixUtilAccumulateStackSizes(prog_group, &stack_sizes)); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK(optixUtilComputeStackSizes(&stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size)); + OPTIX_CHECK(optixPipelineSetStackSize(pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + )); + } + + // + // Set up shader binding table + // + { + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof(RayGenSbtRecord); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&raygen_record), raygen_record_size)); + RayGenSbtRecord rg_sbt; + OPTIX_CHECK(optixSbtRecordPackHeader(raygen_prog_group, &rg_sbt)); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(raygen_record), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice)); + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof(MissSbtRecord); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&miss_record), miss_record_size)); + MissSbtRecord ms_sbt; + OPTIX_CHECK(optixSbtRecordPackHeader(miss_prog_group, &ms_sbt)); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(miss_record), + &ms_sbt, + miss_record_size, + cudaMemcpyHostToDevice)); + + CUdeviceptr hitgroup_record; + size_t hitgroup_record_size = sizeof(HitGroupSbtRecord); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&hitgroup_record), hitgroup_record_size)); + HitGroupSbtRecord hg_sbt; + OPTIX_CHECK(optixSbtRecordPackHeader(hitgroup_prog_group, &hg_sbt)); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(hitgroup_record), + &hg_sbt, + hitgroup_record_size, + cudaMemcpyHostToDevice)); + + sbt.raygenRecord = raygen_record; + sbt.missRecordBase = miss_record; + sbt.missRecordStrideInBytes = sizeof(MissSbtRecord); + sbt.missRecordCount = 1; + sbt.hitgroupRecordBase = hitgroup_record; + sbt.hitgroupRecordStrideInBytes = sizeof(HitGroupSbtRecord); + sbt.hitgroupRecordCount = 1; + } + + CUDA_CHECK(cudaStreamCreate(&stream)); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&d_param), sizeof(ParamsFindTetrahedra))); +} + +FindTetrahedraPipeline::FindTetrahedraPipeline(FindTetrahedraPipeline &&other) noexcept + : device(std::exchange(other.device, -1)), + context(std::exchange(other.context, nullptr)), + pipeline(std::exchange(other.pipeline, nullptr)), + raygen_prog_group(std::exchange(other.raygen_prog_group, nullptr)), + miss_prog_group(std::exchange(other.miss_prog_group, nullptr)), + hitgroup_prog_group(std::exchange(other.hitgroup_prog_group, nullptr)), + module(std::exchange(other.module, nullptr)), + sbt(std::exchange(other.sbt, {})), + stream(std::exchange(other.stream, nullptr)), + d_param(std::exchange(other.d_param, 0)) {} + +FindTetrahedraPipeline::~FindTetrahedraPipeline() noexcept(false) { + const auto device = std::exchange(this->device, -1); + if (device == -1) { + return; + } + if (d_param != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(d_param, 0)))); + if (sbt.raygenRecord != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.raygenRecord, 0)))); + if (sbt.missRecordBase != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.missRecordBase, 0)))); + if (sbt.hitgroupRecordBase != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.hitgroupRecordBase, 0)))); + if (sbt.callablesRecordBase) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.callablesRecordBase, 0)))); + if (sbt.exceptionRecord) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.exceptionRecord, 0)))); + sbt = {}; + if (stream != nullptr) + CUDA_CHECK(cudaStreamDestroy(std::exchange(stream, nullptr))); + if (pipeline != nullptr) + OPTIX_CHECK(optixPipelineDestroy(std::exchange(pipeline, nullptr))); + if (raygen_prog_group != nullptr) + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(raygen_prog_group, nullptr))); + if (miss_prog_group != nullptr) + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(miss_prog_group, nullptr))); + if (hitgroup_prog_group != nullptr) + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(hitgroup_prog_group, nullptr))); + if (module != nullptr) + OPTIX_CHECK(optixModuleDestroy(std::exchange(module, nullptr))); +} + +void FindTetrahedraPipeline::find_tetrahedra(const TetrahedraStructure *tetrahedra_structure, + const size_t num_points, + const float3 *points, + unsigned int *tetrahedra_out, + float3 *barycentric_coordinates_out, + uint4 *vertex_indices_out) { + CUDA_CHECK(cudaSetDevice(device)); + float2 *triangle_barycentric_coordinates; + unsigned int *shared_visited_triangles; + float *triangle_hit_distances; + + ParamsFindTetrahedra params; + params.barycentric_coordinates = barycentric_coordinates_out; + params.ray_origins = points; + params.tetrahedra = tetrahedra_out; + params.vertex_indices = vertex_indices_out; + params.triangle_indices = tetrahedra_structure->triangle_indices(); + params.triangle_tetrahedra = tetrahedra_structure->triangle_tetrahedra(); + params.handle = tetrahedra_structure->gas_handle(); + + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(d_param), + ¶ms, sizeof(params), + cudaMemcpyHostToDevice)); + OPTIX_CHECK(optixLaunch(pipeline, stream, d_param, sizeof(params), &sbt, num_points, 1, 1)); + CUDA_SYNC_CHECK(); + CUDA_CHECK(cudaStreamSynchronize(stream)); +} + +TraceRaysTrianglesPipeline::TraceRaysTrianglesPipeline(const OptixDeviceContext &context, int8_t device) : device(device), context(context) { + // Initialize fields + OptixPipelineCompileOptions pipeline_compile_options = {}; + + // Switch to active device + CUDA_CHECK(cudaSetDevice(device)); + + // Load PTX first to make sure it exists + + char log[2048]; // For error reporting from OptiX creation functions + + // + // Create module + // + { + OptixModuleCompileOptions module_compile_options = {}; + module_compile_options.maxRegisterCount = OPTIX_COMPILE_DEFAULT_MAX_REGISTER_COUNT; + module_compile_options.optLevel = OPTIX_COMPILE_OPTIMIZATION_DEFAULT; + +// The following is not supported in Optix 7.2 +// #define XSTR(x) STR(x) +// #define STR(x) #x +// #pragma message "Optix ABI version is: " XSTR(OPTIX_ABI_VERSION) +#if (OPTIX_ABI_VERSION > 54) + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_MINIMAL; +#else + module_compile_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_LINEINFO; +#endif + + pipeline_compile_options.usesMotionBlur = false; + pipeline_compile_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_GAS; + pipeline_compile_options.numPayloadValues = 1; + // https://forums.developer.nvidia.com/t/how-to-calculate-numattributevalues-of-optixpipelinecompileoptions/110833 + pipeline_compile_options.numAttributeValues = 2; +#ifdef DEBUG // Enables debug exceptions during optix launches. This may incur significant performance cost and should only be done during development. + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_DEBUG | OPTIX_EXCEPTION_FLAG_TRACE_DEPTH | OPTIX_EXCEPTION_FLAG_STACK_OVERFLOW; +#else + pipeline_compile_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; +#endif + pipeline_compile_options.pipelineLaunchParamsVariableName = "params"; + pipeline_compile_options.usesPrimitiveTypeFlags = OPTIX_PRIMITIVE_TYPE_FLAGS_TRIANGLE; + + std::string input = TraceRaysTrianglesPipeline::load_ptx_data(); + size_t sizeof_log = sizeof(log); + + #if (OPTIX_ABI_VERSION > 54) + OPTIX_CHECK(optixModuleCreate( + context, + &module_compile_options, + &pipeline_compile_options, + ptx.c_str(), + ptx.size(), + log, &log_size, + &module + )); + #else + OPTIX_CHECK(optixModuleCreateFromPTX( + context, + &module_compile_options, + &pipeline_compile_options, + ptx.c_str(), + ptx.size(), + log, &log_size, + &module + )); + #endif + + // + // Create program groups + // + { + OptixProgramGroupOptions program_group_options = {}; // Initialize to zeros + + OptixProgramGroupDesc raygen_prog_group_desc = {}; // + raygen_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_RAYGEN; + raygen_prog_group_desc.raygen.module = module; + raygen_prog_group_desc.raygen.entryFunctionName = "__raygen__rg"; + size_t sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate( + context, + &raygen_prog_group_desc, + 1, // num program groups + &program_group_options, + log, + &sizeof_log, + &raygen_prog_group)); + + OptixProgramGroupDesc miss_prog_group_desc = {}; + miss_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_MISS; + miss_prog_group_desc.miss.module = module; + miss_prog_group_desc.miss.entryFunctionName = "__miss__ms"; + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate( + context, + &miss_prog_group_desc, + 1, // num program groups + &program_group_options, + log, + &sizeof_log, + &miss_prog_group)); + + OptixProgramGroupDesc hitgroup_prog_group_desc = {}; + hitgroup_prog_group_desc.kind = OPTIX_PROGRAM_GROUP_KIND_HITGROUP; + hitgroup_prog_group_desc.hitgroup.moduleCH = module; + hitgroup_prog_group_desc.hitgroup.moduleAH = module; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameCH = "__closesthit__ms"; + hitgroup_prog_group_desc.hitgroup.entryFunctionNameAH = "__anyhit__ms"; + sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixProgramGroupCreate( + context, + &hitgroup_prog_group_desc, + 1, // num program groups + &program_group_options, + log, + &sizeof_log, + &hitgroup_prog_group)); + } + + // + // Link pipeline + // + { + const uint32_t max_trace_depth = 1; + OptixProgramGroup program_groups[] = {raygen_prog_group, miss_prog_group, hitgroup_prog_group}; + + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = max_trace_depth; + OptixPipelineLinkOptions pipeline_link_options = {}; + pipeline_link_options.maxTraceDepth = 2; + #if (OPTIX_ABI_VERSION <= 54) + pipeline_link_options.debugLevel = OPTIX_COMPILE_DEBUG_LEVEL_FULL; + #endif + size_t sizeof_log = sizeof(log); + OPTIX_CHECK_LOG(optixPipelineCreate( + context, + &pipeline_compile_options, + &pipeline_link_options, + program_groups, + sizeof(program_groups) / sizeof(program_groups[0]), + log, + &sizeof_log, + &pipeline)); + + OptixStackSizes stack_sizes = {}; + for (auto &prog_group : program_groups) { + OPTIX_CHECK(optixUtilAccumulateStackSizes(prog_group, &stack_sizes)); + } + + uint32_t direct_callable_stack_size_from_traversal; + uint32_t direct_callable_stack_size_from_state; + uint32_t continuation_stack_size; + OPTIX_CHECK(optixUtilComputeStackSizes(&stack_sizes, max_trace_depth, + 0, // maxCCDepth + 0, // maxDCDEpth + &direct_callable_stack_size_from_traversal, + &direct_callable_stack_size_from_state, &continuation_stack_size)); + OPTIX_CHECK(optixPipelineSetStackSize(pipeline, direct_callable_stack_size_from_traversal, + direct_callable_stack_size_from_state, continuation_stack_size, + 1 // maxTraversableDepth + )); + } + + // + // Set up shader binding table + // + { + CUdeviceptr raygen_record; + const size_t raygen_record_size = sizeof(RayGenSbtRecord); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&raygen_record), raygen_record_size)); + RayGenSbtRecord rg_sbt; + OPTIX_CHECK(optixSbtRecordPackHeader(raygen_prog_group, &rg_sbt)); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(raygen_record), + &rg_sbt, + raygen_record_size, + cudaMemcpyHostToDevice)); + + CUdeviceptr miss_record; + size_t miss_record_size = sizeof(MissSbtRecord); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&miss_record), miss_record_size)); + MissSbtRecord ms_sbt; + OPTIX_CHECK(optixSbtRecordPackHeader(miss_prog_group, &ms_sbt)); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(miss_record), + &ms_sbt, + miss_record_size, + cudaMemcpyHostToDevice)); + + CUdeviceptr hitgroup_record; + size_t hitgroup_record_size = sizeof(HitGroupSbtRecord); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&hitgroup_record), hitgroup_record_size)); + HitGroupSbtRecord hg_sbt; + OPTIX_CHECK(optixSbtRecordPackHeader(hitgroup_prog_group, &hg_sbt)); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(hitgroup_record), + &hg_sbt, + hitgroup_record_size, + cudaMemcpyHostToDevice)); + + sbt.raygenRecord = raygen_record; + sbt.missRecordBase = miss_record; + sbt.missRecordStrideInBytes = sizeof(MissSbtRecord); + sbt.missRecordCount = 1; + sbt.hitgroupRecordBase = hitgroup_record; + sbt.hitgroupRecordStrideInBytes = sizeof(HitGroupSbtRecord); + sbt.hitgroupRecordCount = 1; + } + + CUDA_CHECK(cudaStreamCreate(&stream)); + CUDA_CHECK(cudaMalloc(reinterpret_cast(&d_param), sizeof(ParamsTraceRaysTriangles))); +} + +void TraceRaysTrianglesPipeline::trace_rays(const TetrahedraStructure *tetrahedra_structure, + const size_t num_rays, + const unsigned int max_ray_triangles, + const float3 *ray_origins, + const float3 *ray_directions, + unsigned int *num_visited_triangles_out, + unsigned int *visited_triangles_out, + float2 *barycentric_coordinates_out, + float *hit_distances_out, + uint3 *vertex_indices_out) { + ParamsTraceRaysTriangles params; + params.triangle_tetrahedra = tetrahedra_structure->triangle_tetrahedra(); + params.triangle_indices = tetrahedra_structure->triangle_indices(); + params.num_visited_triangles = num_visited_triangles_out; + params.visited_triangles = visited_triangles_out; + params.vertex_indices = vertex_indices_out; + params.max_ray_triangles = max_ray_triangles; + params.barycentric_coordinates = barycentric_coordinates_out; + params.hit_distances = hit_distances_out; + params.handle = tetrahedra_structure->gas_handle(); + params.ray_origins = ray_origins; + params.ray_directions = ray_directions; + + CUDA_CHECK(cudaSetDevice(device)); + CUDA_CHECK(cudaMemcpy( + reinterpret_cast(d_param), + ¶ms, sizeof(params), + cudaMemcpyHostToDevice)); + OPTIX_CHECK(optixLaunch(pipeline, stream, d_param, sizeof(params), &sbt, num_rays, 1, 1)); + CUDA_SYNC_CHECK(); + CUDA_CHECK(cudaStreamSynchronize(stream)); +} + +TraceRaysTrianglesPipeline::TraceRaysTrianglesPipeline(TraceRaysTrianglesPipeline &&other) noexcept + : device(std::exchange(other.device, -1)), + context(std::exchange(other.context, nullptr)), + pipeline(std::exchange(other.pipeline, nullptr)), + raygen_prog_group(std::exchange(other.raygen_prog_group, nullptr)), + miss_prog_group(std::exchange(other.miss_prog_group, nullptr)), + hitgroup_prog_group(std::exchange(other.hitgroup_prog_group, nullptr)), + module(std::exchange(other.module, nullptr)), + sbt(std::exchange(other.sbt, {})), + stream(std::exchange(other.stream, nullptr)), + d_param(std::exchange(other.d_param, 0)) {} + +TraceRaysTrianglesPipeline::~TraceRaysTrianglesPipeline() noexcept(false) { + const auto device = std::exchange(this->device, -1); + if (device == -1) { + return; + } + CUDA_CHECK(cudaSetDevice(device)); + if (d_param != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(d_param, 0)))); + if (sbt.raygenRecord != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.raygenRecord, 0)))); + if (sbt.missRecordBase != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.missRecordBase, 0)))); + if (sbt.hitgroupRecordBase != 0) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.hitgroupRecordBase, 0)))); + if (sbt.callablesRecordBase) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.callablesRecordBase, 0)))); + if (sbt.exceptionRecord) + CUDA_CHECK(cudaFree(reinterpret_cast(std::exchange(sbt.exceptionRecord, 0)))); + sbt = {}; + if (stream != nullptr) + CUDA_CHECK(cudaStreamDestroy(std::exchange(stream, nullptr))); + if (pipeline != nullptr) + OPTIX_CHECK(optixPipelineDestroy(std::exchange(pipeline, nullptr))); + if (raygen_prog_group != nullptr) + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(raygen_prog_group, nullptr))); + if (miss_prog_group != nullptr) + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(miss_prog_group, nullptr))); + if (hitgroup_prog_group != nullptr) + OPTIX_CHECK(optixProgramGroupDestroy(std::exchange(hitgroup_prog_group, nullptr))); + if (module != nullptr) + OPTIX_CHECK(optixModuleDestroy(std::exchange(module, nullptr))); +} diff --git a/Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.h b/Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.h new file mode 100644 index 0000000000..203a441503 --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/src/tetrahedra_tracer.h @@ -0,0 +1,433 @@ +#pragma once +#include +#include +#include +#include +#include + +#ifdef _WIN32 + #include + #include + #ifndef getpid + #define getpid _getpid + #endif +#else + #include +#endif + +#include +#include +#include +#include +#include + +extern "C" { + extern char ptx_code_file[]; + extern char ptx_code_file_find_tetrahedra[]; + extern char ptx_code_file_triangles[]; +} + +class TetrahedraStructure { + public: + TetrahedraStructure() noexcept; + TetrahedraStructure(const OptixDeviceContext &context, const uint8_t device) : device(device), context(context) {} + TetrahedraStructure( + const OptixDeviceContext &context, + const uint8_t device, + const size_t num_vertices, + const size_t num_cells, + const float3 *d_vertices, + const uint4 *cells) : TetrahedraStructure(context, device) { + build(num_vertices, num_cells, d_vertices, cells); + } + + ~TetrahedraStructure() noexcept(false); + TetrahedraStructure(const TetrahedraStructure &) = delete; + TetrahedraStructure &operator=(const TetrahedraStructure &) = delete; + TetrahedraStructure(TetrahedraStructure &&other) noexcept; + TetrahedraStructure &operator=(TetrahedraStructure &&other) { + using std::swap; + if (this != &other) { + TetrahedraStructure tmp(std::move(other)); + swap(tmp, *this); + } + return *this; + } + + friend void swap(TetrahedraStructure &first, TetrahedraStructure &second) { + using std::swap; + swap(first.context, second.context); + swap(first.device, second.device); + swap(first.num_vertices, second.num_vertices); + swap(first.num_cells, second.num_cells); + swap(first.gas_handle_, second.gas_handle_); + swap(first.d_gas_output_buffer, second.d_gas_output_buffer); + swap(first.tetrahedra_vertices, second.tetrahedra_vertices); + swap(first.triangle_indices_, second.triangle_indices_); + swap(first.triangle_tetrahedra_, second.triangle_tetrahedra_); + } + + OptixTraversableHandle gas_handle() const { + if (!defined()) { + throw std::runtime_error("TetrahedraStructure is not initialized"); + } + return gas_handle_; + } + + const uint3 *triangle_indices() const { return triangle_indices_; } + const uint2 *triangle_tetrahedra() const { return triangle_tetrahedra_; } + bool defined() const { return gas_handle_ != 0; } + + private: + void build( + const size_t num_vertices, + const size_t num_cells, + const float3 *d_vertices, + const uint4 *cells); + + void release(); + + OptixDeviceContext context = nullptr; + int8_t device = -1; + size_t num_vertices = 0; + size_t num_cells = 0; + OptixTraversableHandle gas_handle_ = 0; + CUdeviceptr d_gas_output_buffer = 0; + const float3 *tetrahedra_vertices = nullptr; + uint3 *triangle_indices_ = nullptr; + uint2 *triangle_tetrahedra_ = nullptr; +}; + +class TraceRaysPipeline { + public: + TraceRaysPipeline() = default; + TraceRaysPipeline(const OptixDeviceContext &context, int8_t device); + TraceRaysPipeline(const TraceRaysPipeline &) = delete; + TraceRaysPipeline &operator=(const TraceRaysPipeline &) = delete; + TraceRaysPipeline(TraceRaysPipeline &&other) noexcept; + TraceRaysPipeline &operator=(TraceRaysPipeline &&other) { + using std::swap; + if (this != &other) { + TraceRaysPipeline tmp(std::move(other)); + swap(tmp, *this); + } + return *this; + } + ~TraceRaysPipeline() noexcept(false); + + friend void swap(TraceRaysPipeline &first, TraceRaysPipeline &second) { + using std::swap; + swap(first.context, second.context); + swap(first.device, second.device); + swap(first.module, second.module); + swap(first.sbt, second.sbt); + swap(first.pipeline, second.pipeline); + swap(first.d_param, second.d_param); + swap(first.stream, second.stream); + swap(first.raygen_prog_group, second.raygen_prog_group); + swap(first.miss_prog_group, second.miss_prog_group); + swap(first.hitgroup_prog_group, second.hitgroup_prog_group); + swap(first.eps, second.eps); + } + + void trace_rays( + const TetrahedraStructure *tetrahedra_structure, + const size_t num_rays, + const unsigned int max_ray_triangles, + const float3 *ray_origins, + const float3 *ray_directions, + unsigned int *num_visited_cells_out, + unsigned int *visited_cells_out, + float3 *barycentric_coordinates_out, + float2 *hit_distances_out, + uint4 *vertex_indices_out); + + private: + OptixDeviceContext context = nullptr; + int8_t device = -1; + + OptixModule module = nullptr; + OptixShaderBindingTable sbt = {}; + OptixPipeline pipeline = nullptr; + CUdeviceptr d_param = 0; + CUstream stream = nullptr; + + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + OptixProgramGroup hitgroup_prog_group = nullptr; + float eps = 1e-6f; + + static std::string load_ptx_data() { + return std::string(ptx_code_file); + } +}; + +class TraceRaysTrianglesPipeline { + public: + TraceRaysTrianglesPipeline() = default; + TraceRaysTrianglesPipeline(const OptixDeviceContext &context, int8_t device); + TraceRaysTrianglesPipeline(const TraceRaysTrianglesPipeline &) = delete; + TraceRaysTrianglesPipeline &operator=(const TraceRaysTrianglesPipeline &) = delete; + TraceRaysTrianglesPipeline(TraceRaysTrianglesPipeline &&other) noexcept; + TraceRaysTrianglesPipeline &operator=(TraceRaysTrianglesPipeline &&other) { + using std::swap; + if (this != &other) { + TraceRaysTrianglesPipeline tmp(std::move(other)); + swap(tmp, *this); + } + return *this; + } + ~TraceRaysTrianglesPipeline() noexcept(false); + + friend void swap(TraceRaysTrianglesPipeline &first, TraceRaysTrianglesPipeline &second) { + using std::swap; + swap(first.context, second.context); + swap(first.device, second.device); + swap(first.module, second.module); + swap(first.sbt, second.sbt); + swap(first.pipeline, second.pipeline); + swap(first.d_param, second.d_param); + swap(first.stream, second.stream); + swap(first.raygen_prog_group, second.raygen_prog_group); + swap(first.miss_prog_group, second.miss_prog_group); + swap(first.hitgroup_prog_group, second.hitgroup_prog_group); + } + + void trace_rays( + const TetrahedraStructure *tetrahedra_structure, + const size_t num_rays, + const unsigned int max_ray_triangles, + const float3 *ray_origins, + const float3 *ray_directions, + unsigned int *num_visited_triangles_out, + unsigned int *visited_triangles_out, + float2 *barycentric_coordinates_out, + float *hit_distances_out, + uint3 *vertex_indices_out); + + private: + OptixDeviceContext context = nullptr; + int8_t device = -1; + + OptixModule module = nullptr; + OptixShaderBindingTable sbt = {}; + OptixPipeline pipeline = nullptr; + CUdeviceptr d_param = 0; + CUstream stream = nullptr; + + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + OptixProgramGroup hitgroup_prog_group = nullptr; + + static std::string load_ptx_data() { + return std::string(ptx_code_file_triangles); + } +}; + +class FindTetrahedraPipeline { + public: + FindTetrahedraPipeline() = default; + FindTetrahedraPipeline(const OptixDeviceContext &context, int8_t device); + FindTetrahedraPipeline(const FindTetrahedraPipeline &) = delete; + FindTetrahedraPipeline &operator=(const FindTetrahedraPipeline &) = delete; + FindTetrahedraPipeline(FindTetrahedraPipeline &&other) noexcept; + FindTetrahedraPipeline &operator=(FindTetrahedraPipeline &&other) { + using std::swap; + if (this != &other) { + FindTetrahedraPipeline tmp(std::move(other)); + swap(tmp, *this); + } + return *this; + } + ~FindTetrahedraPipeline() noexcept(false); + + friend void swap(FindTetrahedraPipeline &first, FindTetrahedraPipeline &second) { + using std::swap; + swap(first.context, second.context); + swap(first.device, second.device); + swap(first.module, second.module); + swap(first.sbt, second.sbt); + swap(first.pipeline, second.pipeline); + swap(first.d_param, second.d_param); + swap(first.stream, second.stream); + swap(first.raygen_prog_group, second.raygen_prog_group); + swap(first.miss_prog_group, second.miss_prog_group); + swap(first.hitgroup_prog_group, second.hitgroup_prog_group); + swap(first.eps, second.eps); + } + + void find_tetrahedra( + const TetrahedraStructure *tetrahedra_structure, + const size_t num_points, + const float3 *points, + unsigned int *tetrahedra_out, + float3 *barycentric_coordinates_out, + uint4 *vertex_indices_out); + + private: + OptixDeviceContext context = nullptr; + int8_t device = -1; + + OptixModule module = nullptr; + OptixShaderBindingTable sbt = {}; + OptixPipeline pipeline = nullptr; + CUdeviceptr d_param = 0; + CUstream stream = nullptr; + + OptixProgramGroup raygen_prog_group = nullptr; + OptixProgramGroup miss_prog_group = nullptr; + OptixProgramGroup hitgroup_prog_group = nullptr; + float eps = 1e-6f; + + static std::string load_ptx_data() { + return std::string(ptx_code_file_find_tetrahedra); + } +}; + +class TetrahedraTracer { + public: + TetrahedraTracer(int8_t device); + ~TetrahedraTracer() noexcept(false); + TetrahedraTracer(const TetrahedraTracer &) = delete; + TetrahedraTracer &operator=(const TetrahedraTracer &) = delete; + TetrahedraTracer(TetrahedraTracer &&other) noexcept; + TetrahedraTracer &operator=(TetrahedraTracer &&other) { + using std::swap; + if (this != &other) { + TetrahedraTracer tmp(std::move(other)); + swap(tmp, *this); + } + return *this; + } + + void load_tetrahedra( + const size_t num_vertices, + const size_t num_cells, + const float3 *d_vertices, + const uint4 *cells) { + tetrahedra_structure = std::move(TetrahedraStructure(context, device, num_vertices, num_cells, d_vertices, cells)); + } + + void trace_rays( + const size_t num_rays, + const unsigned int max_ray_triangles, + const float3 *ray_origins, + const float3 *ray_directions, + unsigned int *num_visited_cells_out, + unsigned int *visited_cells_out, + float3 *barycentric_coordinates_out, + float2 *hit_distances_out, + uint4 *vertex_indices_out) { + trace_rays_pipeline.trace_rays( + &tetrahedra_structure, + num_rays, + max_ray_triangles, + ray_origins, + ray_directions, + num_visited_cells_out, + visited_cells_out, + barycentric_coordinates_out, + hit_distances_out, + vertex_indices_out); + } + + void trace_rays_triangles( + const size_t num_rays, + const unsigned int max_ray_triangles, + const float3 *ray_origins, + const float3 *ray_directions, + unsigned int *num_visited_triangles_out, + unsigned int *visited_triangles_out, + float2 *barycentric_coordinates_out, + float *hit_distances_out, + uint3 *vertex_indices_out) { + trace_rays_triangles_pipeline.trace_rays( + &tetrahedra_structure, + num_rays, + max_ray_triangles, + ray_origins, + ray_directions, + num_visited_triangles_out, + visited_triangles_out, + barycentric_coordinates_out, + hit_distances_out, + vertex_indices_out); + } + + void find_tetrahedra( + const size_t num_points, + const float3 *points, + unsigned int *tetrahedra_out, + float3 *barycentric_coordinates_out, + uint4 *vertex_indices_out) { + find_tetrahedra_pipeline.find_tetrahedra( + &tetrahedra_structure, + num_points, + points, + tetrahedra_out, + barycentric_coordinates_out, + vertex_indices_out); + } + + private: + int8_t device = -1; + OptixDeviceContext context = nullptr; + + TetrahedraStructure tetrahedra_structure; + TraceRaysPipeline trace_rays_pipeline; + TraceRaysTrianglesPipeline trace_rays_triangles_pipeline; + FindTetrahedraPipeline find_tetrahedra_pipeline; +}; + +void find_matched_cells( + const size_t num_rays, + const size_t num_samples_per_ray, + const size_t max_visited_cells, + const uint4 *cells, + const unsigned int *num_visited_cells, + const unsigned int *visited_cells, + const float2 *hit_distances, + const float3 *barycentric_coordinates, + const float *distances, + const uint4 *vertex_indices, + unsigned int *matched_cells_out, + uint4 *matched_vertices_out, + bool *mask_out, + float3 *barycentric_coordinates_out); + +template +void interpolate_values( + const uint32_t num_vertices, + const uint32_t num_values, + const uint32_t field_dim, + const uint32_t *vertex_indices, + const float *barycentric_coordinates, + const float *field, + float *result); + +template +void interpolate_values_backward( + const uint32_t num_vertices, + const uint32_t num_values, + const uint32_t field_dim, + const uint32_t *vertex_indices, + const float *barycentric_coordinates, + const float *grad_in, + float *field_grad_out); + +template +void gather_uint32( + const uint32_t num_values, + const uint32_t num_indices, + const uint32_t *indices, + const scalar_t *values, + scalar_t *result); + +template +void scatter_ema_uint32( + const uint32_t num_result, + const uint32_t num_indices, + const uint32_t *indices, + const scalar_t decay, + const scalar_t *values, + scalar_t *result); \ No newline at end of file diff --git a/Extra-Methods-Patches/tetra-nerf/src/utils/vec_math.h b/Extra-Methods-Patches/tetra-nerf/src/utils/vec_math.h new file mode 100644 index 0000000000..eae3247d6f --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/src/utils/vec_math.h @@ -0,0 +1,2635 @@ +// +// Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved. +// +// 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. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors 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 ``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 OWNER 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. +// + + +#pragma once + +#ifdef _WIN32 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#endif + +#include "preprocessor.h" + +#include +#include + +#if !defined(__CUDACC_RTC__) +#include +#include +#endif + +#ifdef _WIN32 +#ifdef min +#undef min +#endif +#ifdef max +#undef max +#endif +#endif + +/* scalar functions used in vector functions */ +#ifndef M_PIf +#define M_PIf 3.14159265358979323846f +#endif +#ifndef M_PI_2f +#define M_PI_2f 1.57079632679489661923f +#endif +#ifndef M_1_PIf +#define M_1_PIf 0.318309886183790671538f +#endif + + +#if !defined(__CUDACC__) + +INLINE HOSTDEVICE int max(int a, int b) +{ + return a > b ? a : b; +} + +INLINE HOSTDEVICE int min(int a, int b) +{ + return a < b ? a : b; +} + +INLINE HOSTDEVICE long long max(long long a, long long b) +{ + return a > b ? a : b; +} + +INLINE HOSTDEVICE long long min(long long a, long long b) +{ + return a < b ? a : b; +} + +INLINE HOSTDEVICE unsigned int max(unsigned int a, unsigned int b) +{ + return a > b ? a : b; +} + +INLINE HOSTDEVICE unsigned int min(unsigned int a, unsigned int b) +{ + return a < b ? a : b; +} + +INLINE HOSTDEVICE unsigned long long max(unsigned long long a, unsigned long long b) +{ + return a > b ? a : b; +} + +INLINE HOSTDEVICE unsigned long long min(unsigned long long a, unsigned long long b) +{ + return a < b ? a : b; +} + + +/** lerp */ +INLINE HOSTDEVICE float lerp(const float a, const float b, const float t) +{ + return a + t*(b-a); +} + +/** bilerp */ +INLINE HOSTDEVICE float bilerp(const float x00, const float x10, const float x01, const float x11, + const float u, const float v) +{ + return lerp( lerp( x00, x10, u ), lerp( x01, x11, u ), v ); +} + +template +INLINE HOSTDEVICE IntegerType roundUp(IntegerType x, IntegerType y) +{ + return ( ( x + y - 1 ) / y ) * y; +} + +#endif + +/** clamp */ +INLINE HOSTDEVICE float clamp( const float f, const float a, const float b ) +{ + return fmaxf( a, fminf( f, b ) ); +} + + +/* float2 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE float2 make_float2(const float s) +{ + return make_float2(s, s); +} +INLINE HOSTDEVICE float2 make_float2(const int2& a) +{ + return make_float2(float(a.x), float(a.y)); +} +INLINE HOSTDEVICE float2 make_float2(const uint2& a) +{ + return make_float2(float(a.x), float(a.y)); +} +/** @} */ + +/** negate */ +INLINE HOSTDEVICE float2 operator-(const float2& a) +{ + return make_float2(-a.x, -a.y); +} + +/** min +* @{ +*/ +INLINE HOSTDEVICE float2 fminf(const float2& a, const float2& b) +{ + return make_float2(fminf(a.x,b.x), fminf(a.y,b.y)); +} +INLINE HOSTDEVICE float fminf(const float2& a) +{ + return fminf(a.x, a.y); +} +/** @} */ + +/** max +* @{ +*/ +INLINE HOSTDEVICE float2 fmaxf(const float2& a, const float2& b) +{ + return make_float2(fmaxf(a.x,b.x), fmaxf(a.y,b.y)); +} +INLINE HOSTDEVICE float fmaxf(const float2& a) +{ + return fmaxf(a.x, a.y); +} +/** @} */ + +/** add +* @{ +*/ +INLINE HOSTDEVICE float2 operator+(const float2& a, const float2& b) +{ + return make_float2(a.x + b.x, a.y + b.y); +} +INLINE HOSTDEVICE float2 operator+(const float2& a, const float b) +{ + return make_float2(a.x + b, a.y + b); +} +INLINE HOSTDEVICE float2 operator+(const float a, const float2& b) +{ + return make_float2(a + b.x, a + b.y); +} +INLINE HOSTDEVICE void operator+=(float2& a, const float2& b) +{ + a.x += b.x; a.y += b.y; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE float2 operator-(const float2& a, const float2& b) +{ + return make_float2(a.x - b.x, a.y - b.y); +} +INLINE HOSTDEVICE float2 operator-(const float2& a, const float b) +{ + return make_float2(a.x - b, a.y - b); +} +INLINE HOSTDEVICE float2 operator-(const float a, const float2& b) +{ + return make_float2(a - b.x, a - b.y); +} +INLINE HOSTDEVICE void operator-=(float2& a, const float2& b) +{ + a.x -= b.x; a.y -= b.y; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE float2 operator*(const float2& a, const float2& b) +{ + return make_float2(a.x * b.x, a.y * b.y); +} +INLINE HOSTDEVICE float2 operator*(const float2& a, const float s) +{ + return make_float2(a.x * s, a.y * s); +} +INLINE HOSTDEVICE float2 operator*(const float s, const float2& a) +{ + return make_float2(a.x * s, a.y * s); +} +INLINE HOSTDEVICE void operator*=(float2& a, const float2& s) +{ + a.x *= s.x; a.y *= s.y; +} +INLINE HOSTDEVICE void operator*=(float2& a, const float s) +{ + a.x *= s; a.y *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE float2 operator/(const float2& a, const float2& b) +{ + return make_float2(a.x / b.x, a.y / b.y); +} +INLINE HOSTDEVICE float2 operator/(const float2& a, const float s) +{ + float inv = 1.0f / s; + return a * inv; +} +INLINE HOSTDEVICE float2 operator/(const float s, const float2& a) +{ + return make_float2( s/a.x, s/a.y ); +} +INLINE HOSTDEVICE void operator/=(float2& a, const float s) +{ + float inv = 1.0f / s; + a *= inv; +} +/** @} */ + +/** lerp */ +INLINE HOSTDEVICE float2 lerp(const float2& a, const float2& b, const float t) +{ + return a + t*(b-a); +} + +/** bilerp */ +INLINE HOSTDEVICE float2 bilerp(const float2& x00, const float2& x10, const float2& x01, const float2& x11, + const float u, const float v) +{ + return lerp( lerp( x00, x10, u ), lerp( x01, x11, u ), v ); +} + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE float2 clamp(const float2& v, const float a, const float b) +{ + return make_float2(clamp(v.x, a, b), clamp(v.y, a, b)); +} + +INLINE HOSTDEVICE float2 clamp(const float2& v, const float2& a, const float2& b) +{ + return make_float2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y)); +} +/** @} */ + +/** dot product */ +INLINE HOSTDEVICE float dot(const float2& a, const float2& b) +{ + return a.x * b.x + a.y * b.y; +} + +/** length */ +INLINE HOSTDEVICE float length(const float2& v) +{ + return sqrtf(dot(v, v)); +} + +/** normalize */ +INLINE HOSTDEVICE float2 normalize(const float2& v) +{ + float invLen = 1.0f / sqrtf(dot(v, v)); + return v * invLen; +} + +/** floor */ +INLINE HOSTDEVICE float2 floor(const float2& v) +{ + return make_float2(::floorf(v.x), ::floorf(v.y)); +} + +/** reflect */ +INLINE HOSTDEVICE float2 reflect(const float2& i, const float2& n) +{ + return i - 2.0f * n * dot(n,i); +} + +/** Faceforward +* Returns N if dot(i, nref) > 0; else -N; +* Typical usage is N = faceforward(N, -ray.dir, N); +* Note that this is opposite of what faceforward does in Cg and GLSL */ +INLINE HOSTDEVICE float2 faceforward(const float2& n, const float2& i, const float2& nref) +{ + return n * copysignf( 1.0f, dot(i, nref) ); +} + +/** exp */ +INLINE HOSTDEVICE float2 expf(const float2& v) +{ + return make_float2(::expf(v.x), ::expf(v.y)); +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE float getByIndex(const float2& v, int i) +{ + return ((float*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(float2& v, int i, float x) +{ + ((float*)(&v))[i] = x; +} + + +/* float3 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE float3 make_float3(const float s) +{ + return make_float3(s, s, s); +} +INLINE HOSTDEVICE float3 make_float3(const float2& a) +{ + return make_float3(a.x, a.y, 0.0f); +} +INLINE HOSTDEVICE float3 make_float3(const int3& a) +{ + return make_float3(float(a.x), float(a.y), float(a.z)); +} +INLINE HOSTDEVICE float3 make_float3(const uint3& a) +{ + return make_float3(float(a.x), float(a.y), float(a.z)); +} +/** @} */ + +/** negate */ +INLINE HOSTDEVICE float3 operator-(const float3& a) +{ + return make_float3(-a.x, -a.y, -a.z); +} + +/** min +* @{ +*/ +INLINE HOSTDEVICE float3 fminf(const float3& a, const float3& b) +{ + return make_float3(fminf(a.x,b.x), fminf(a.y,b.y), fminf(a.z,b.z)); +} +INLINE HOSTDEVICE float fminf(const float3& a) +{ + return fminf(fminf(a.x, a.y), a.z); +} +/** @} */ + +/** max +* @{ +*/ +INLINE HOSTDEVICE float3 fmaxf(const float3& a, const float3& b) +{ + return make_float3(fmaxf(a.x,b.x), fmaxf(a.y,b.y), fmaxf(a.z,b.z)); +} +INLINE HOSTDEVICE float fmaxf(const float3& a) +{ + return fmaxf(fmaxf(a.x, a.y), a.z); +} +/** @} */ + +/** add +* @{ +*/ +INLINE HOSTDEVICE float3 operator+(const float3& a, const float3& b) +{ + return make_float3(a.x + b.x, a.y + b.y, a.z + b.z); +} +INLINE HOSTDEVICE float3 operator+(const float3& a, const float b) +{ + return make_float3(a.x + b, a.y + b, a.z + b); +} +INLINE HOSTDEVICE float3 operator+(const float a, const float3& b) +{ + return make_float3(a + b.x, a + b.y, a + b.z); +} +INLINE HOSTDEVICE void operator+=(float3& a, const float3& b) +{ + a.x += b.x; a.y += b.y; a.z += b.z; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE float3 operator-(const float3& a, const float3& b) +{ + return make_float3(a.x - b.x, a.y - b.y, a.z - b.z); +} +INLINE HOSTDEVICE float3 operator-(const float3& a, const float b) +{ + return make_float3(a.x - b, a.y - b, a.z - b); +} +INLINE HOSTDEVICE float3 operator-(const float a, const float3& b) +{ + return make_float3(a - b.x, a - b.y, a - b.z); +} +INLINE HOSTDEVICE void operator-=(float3& a, const float3& b) +{ + a.x -= b.x; a.y -= b.y; a.z -= b.z; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE float3 operator*(const float3& a, const float3& b) +{ + return make_float3(a.x * b.x, a.y * b.y, a.z * b.z); +} +INLINE HOSTDEVICE float3 operator*(const float3& a, const float s) +{ + return make_float3(a.x * s, a.y * s, a.z * s); +} +INLINE HOSTDEVICE float3 operator*(const float s, const float3& a) +{ + return make_float3(a.x * s, a.y * s, a.z * s); +} +INLINE HOSTDEVICE void operator*=(float3& a, const float3& s) +{ + a.x *= s.x; a.y *= s.y; a.z *= s.z; +} +INLINE HOSTDEVICE void operator*=(float3& a, const float s) +{ + a.x *= s; a.y *= s; a.z *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE float3 operator/(const float3& a, const float3& b) +{ + return make_float3(a.x / b.x, a.y / b.y, a.z / b.z); +} +INLINE HOSTDEVICE float3 operator/(const float3& a, const float s) +{ + float inv = 1.0f / s; + return a * inv; +} +INLINE HOSTDEVICE float3 operator/(const float s, const float3& a) +{ + return make_float3( s/a.x, s/a.y, s/a.z ); +} +INLINE HOSTDEVICE void operator/=(float3& a, const float s) +{ + float inv = 1.0f / s; + a *= inv; +} +/** @} */ + +/** lerp */ +INLINE HOSTDEVICE float3 lerp(const float3& a, const float3& b, const float t) +{ + return a + t*(b-a); +} + +/** bilerp */ +INLINE HOSTDEVICE float3 bilerp(const float3& x00, const float3& x10, const float3& x01, const float3& x11, + const float u, const float v) +{ + return lerp( lerp( x00, x10, u ), lerp( x01, x11, u ), v ); +} + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE float3 clamp(const float3& v, const float a, const float b) +{ + return make_float3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b)); +} + +INLINE HOSTDEVICE float3 clamp(const float3& v, const float3& a, const float3& b) +{ + return make_float3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z)); +} +/** @} */ + +/** dot product */ +INLINE HOSTDEVICE float dot(const float3& a, const float3& b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z; +} + +/** cross product */ +INLINE HOSTDEVICE float3 cross(const float3& a, const float3& b) +{ + return make_float3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x); +} + +/** length */ +INLINE HOSTDEVICE float length(const float3& v) +{ + return sqrtf(dot(v, v)); +} + +/** normalize */ +INLINE HOSTDEVICE float3 normalize(const float3& v) +{ + float invLen = 1.0f / sqrtf(dot(v, v)); + return v * invLen; +} + +/** floor */ +INLINE HOSTDEVICE float3 floor(const float3& v) +{ + return make_float3(::floorf(v.x), ::floorf(v.y), ::floorf(v.z)); +} + +/** reflect */ +INLINE HOSTDEVICE float3 reflect(const float3& i, const float3& n) +{ + return i - 2.0f * n * dot(n,i); +} + +/** Faceforward +* Returns N if dot(i, nref) > 0; else -N; +* Typical usage is N = faceforward(N, -ray.dir, N); +* Note that this is opposite of what faceforward does in Cg and GLSL */ +INLINE HOSTDEVICE float3 faceforward(const float3& n, const float3& i, const float3& nref) +{ + return n * copysignf( 1.0f, dot(i, nref) ); +} + +/** exp */ +INLINE HOSTDEVICE float3 expf(const float3& v) +{ + return make_float3(::expf(v.x), ::expf(v.y), ::expf(v.z)); +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE float getByIndex(const float3& v, int i) +{ + return ((float*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(float3& v, int i, float x) +{ + ((float*)(&v))[i] = x; +} + +/* float4 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE float4 make_float4(const float s) +{ + return make_float4(s, s, s, s); +} +INLINE HOSTDEVICE float4 make_float4(const float3& a) +{ + return make_float4(a.x, a.y, a.z, 0.0f); +} +INLINE HOSTDEVICE float4 make_float4(const int4& a) +{ + return make_float4(float(a.x), float(a.y), float(a.z), float(a.w)); +} +INLINE HOSTDEVICE float4 make_float4(const uint4& a) +{ + return make_float4(float(a.x), float(a.y), float(a.z), float(a.w)); +} +/** @} */ + +/** negate */ +INLINE HOSTDEVICE float4 operator-(const float4& a) +{ + return make_float4(-a.x, -a.y, -a.z, -a.w); +} + +/** min +* @{ +*/ +INLINE HOSTDEVICE float4 fminf(const float4& a, const float4& b) +{ + return make_float4(fminf(a.x,b.x), fminf(a.y,b.y), fminf(a.z,b.z), fminf(a.w,b.w)); +} +INLINE HOSTDEVICE float fminf(const float4& a) +{ + return fminf(fminf(a.x, a.y), fminf(a.z, a.w)); +} +/** @} */ + +/** max +* @{ +*/ +INLINE HOSTDEVICE float4 fmaxf(const float4& a, const float4& b) +{ + return make_float4(fmaxf(a.x,b.x), fmaxf(a.y,b.y), fmaxf(a.z,b.z), fmaxf(a.w,b.w)); +} +INLINE HOSTDEVICE float fmaxf(const float4& a) +{ + return fmaxf(fmaxf(a.x, a.y), fmaxf(a.z, a.w)); +} +/** @} */ + +/** add +* @{ +*/ +INLINE HOSTDEVICE float4 operator+(const float4& a, const float4& b) +{ + return make_float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); +} +INLINE HOSTDEVICE float4 operator+(const float4& a, const float b) +{ + return make_float4(a.x + b, a.y + b, a.z + b, a.w + b); +} +INLINE HOSTDEVICE float4 operator+(const float a, const float4& b) +{ + return make_float4(a + b.x, a + b.y, a + b.z, a + b.w); +} +INLINE HOSTDEVICE void operator+=(float4& a, const float4& b) +{ + a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE float4 operator-(const float4& a, const float4& b) +{ + return make_float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); +} +INLINE HOSTDEVICE float4 operator-(const float4& a, const float b) +{ + return make_float4(a.x - b, a.y - b, a.z - b, a.w - b); +} +INLINE HOSTDEVICE float4 operator-(const float a, const float4& b) +{ + return make_float4(a - b.x, a - b.y, a - b.z, a - b.w); +} +INLINE HOSTDEVICE void operator-=(float4& a, const float4& b) +{ + a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE float4 operator*(const float4& a, const float4& s) +{ + return make_float4(a.x * s.x, a.y * s.y, a.z * s.z, a.w * s.w); +} +INLINE HOSTDEVICE float4 operator*(const float4& a, const float s) +{ + return make_float4(a.x * s, a.y * s, a.z * s, a.w * s); +} +INLINE HOSTDEVICE float4 operator*(const float s, const float4& a) +{ + return make_float4(a.x * s, a.y * s, a.z * s, a.w * s); +} +INLINE HOSTDEVICE void operator*=(float4& a, const float4& s) +{ + a.x *= s.x; a.y *= s.y; a.z *= s.z; a.w *= s.w; +} +INLINE HOSTDEVICE void operator*=(float4& a, const float s) +{ + a.x *= s; a.y *= s; a.z *= s; a.w *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE float4 operator/(const float4& a, const float4& b) +{ + return make_float4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); +} +INLINE HOSTDEVICE float4 operator/(const float4& a, const float s) +{ + float inv = 1.0f / s; + return a * inv; +} +INLINE HOSTDEVICE float4 operator/(const float s, const float4& a) +{ + return make_float4( s/a.x, s/a.y, s/a.z, s/a.w ); +} +INLINE HOSTDEVICE void operator/=(float4& a, const float s) +{ + float inv = 1.0f / s; + a *= inv; +} +/** @} */ + +/** lerp */ +INLINE HOSTDEVICE float4 lerp(const float4& a, const float4& b, const float t) +{ + return a + t*(b-a); +} + +/** bilerp */ +INLINE HOSTDEVICE float4 bilerp(const float4& x00, const float4& x10, const float4& x01, const float4& x11, + const float u, const float v) +{ + return lerp( lerp( x00, x10, u ), lerp( x01, x11, u ), v ); +} + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE float4 clamp(const float4& v, const float a, const float b) +{ + return make_float4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b)); +} + +INLINE HOSTDEVICE float4 clamp(const float4& v, const float4& a, const float4& b) +{ + return make_float4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w)); +} +/** @} */ + +/** dot product */ +INLINE HOSTDEVICE float dot(const float4& a, const float4& b) +{ + return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; +} + +/** length */ +INLINE HOSTDEVICE float length(const float4& r) +{ + return sqrtf(dot(r, r)); +} + +/** normalize */ +INLINE HOSTDEVICE float4 normalize(const float4& v) +{ + float invLen = 1.0f / sqrtf(dot(v, v)); + return v * invLen; +} + +/** floor */ +INLINE HOSTDEVICE float4 floor(const float4& v) +{ + return make_float4(::floorf(v.x), ::floorf(v.y), ::floorf(v.z), ::floorf(v.w)); +} + +/** reflect */ +INLINE HOSTDEVICE float4 reflect(const float4& i, const float4& n) +{ + return i - 2.0f * n * dot(n,i); +} + +/** +* Faceforward +* Returns N if dot(i, nref) > 0; else -N; +* Typical usage is N = faceforward(N, -ray.dir, N); +* Note that this is opposite of what faceforward does in Cg and GLSL +*/ +INLINE HOSTDEVICE float4 faceforward(const float4& n, const float4& i, const float4& nref) +{ + return n * copysignf( 1.0f, dot(i, nref) ); +} + +/** exp */ +INLINE HOSTDEVICE float4 expf(const float4& v) +{ + return make_float4(::expf(v.x), ::expf(v.y), ::expf(v.z), ::expf(v.w)); +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE float getByIndex(const float4& v, int i) +{ + return ((float*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(float4& v, int i, float x) +{ + ((float*)(&v))[i] = x; +} + + +/* int functions */ +/******************************************************************************/ + +/** clamp */ +INLINE HOSTDEVICE int clamp(const int f, const int a, const int b) +{ + return max(a, min(f, b)); +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE int getByIndex(const int1& v, int i) +{ + return ((int*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(int1& v, int i, int x) +{ + ((int*)(&v))[i] = x; +} + + +/* int2 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE int2 make_int2(const int s) +{ + return make_int2(s, s); +} +INLINE HOSTDEVICE int2 make_int2(const float2& a) +{ + return make_int2(int(a.x), int(a.y)); +} +/** @} */ + +/** negate */ +INLINE HOSTDEVICE int2 operator-(const int2& a) +{ + return make_int2(-a.x, -a.y); +} + +/** min */ +INLINE HOSTDEVICE int2 min(const int2& a, const int2& b) +{ + return make_int2(min(a.x,b.x), min(a.y,b.y)); +} + +/** max */ +INLINE HOSTDEVICE int2 max(const int2& a, const int2& b) +{ + return make_int2(max(a.x,b.x), max(a.y,b.y)); +} + +/** add +* @{ +*/ +INLINE HOSTDEVICE int2 operator+(const int2& a, const int2& b) +{ + return make_int2(a.x + b.x, a.y + b.y); +} +INLINE HOSTDEVICE void operator+=(int2& a, const int2& b) +{ + a.x += b.x; a.y += b.y; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE int2 operator-(const int2& a, const int2& b) +{ + return make_int2(a.x - b.x, a.y - b.y); +} +INLINE HOSTDEVICE int2 operator-(const int2& a, const int b) +{ + return make_int2(a.x - b, a.y - b); +} +INLINE HOSTDEVICE void operator-=(int2& a, const int2& b) +{ + a.x -= b.x; a.y -= b.y; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE int2 operator*(const int2& a, const int2& b) +{ + return make_int2(a.x * b.x, a.y * b.y); +} +INLINE HOSTDEVICE int2 operator*(const int2& a, const int s) +{ + return make_int2(a.x * s, a.y * s); +} +INLINE HOSTDEVICE int2 operator*(const int s, const int2& a) +{ + return make_int2(a.x * s, a.y * s); +} +INLINE HOSTDEVICE void operator*=(int2& a, const int s) +{ + a.x *= s; a.y *= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE int2 clamp(const int2& v, const int a, const int b) +{ + return make_int2(clamp(v.x, a, b), clamp(v.y, a, b)); +} + +INLINE HOSTDEVICE int2 clamp(const int2& v, const int2& a, const int2& b) +{ + return make_int2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const int2& a, const int2& b) +{ + return a.x == b.x && a.y == b.y; +} + +INLINE HOSTDEVICE bool operator!=(const int2& a, const int2& b) +{ + return a.x != b.x || a.y != b.y; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE int getByIndex(const int2& v, int i) +{ + return ((int*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(int2& v, int i, int x) +{ + ((int*)(&v))[i] = x; +} + + +/* int3 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE int3 make_int3(const int s) +{ + return make_int3(s, s, s); +} +INLINE HOSTDEVICE int3 make_int3(const float3& a) +{ + return make_int3(int(a.x), int(a.y), int(a.z)); +} +/** @} */ + +/** negate */ +INLINE HOSTDEVICE int3 operator-(const int3& a) +{ + return make_int3(-a.x, -a.y, -a.z); +} + +/** min */ +INLINE HOSTDEVICE int3 min(const int3& a, const int3& b) +{ + return make_int3(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z)); +} + +/** max */ +INLINE HOSTDEVICE int3 max(const int3& a, const int3& b) +{ + return make_int3(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z)); +} + +/** add +* @{ +*/ +INLINE HOSTDEVICE int3 operator+(const int3& a, const int3& b) +{ + return make_int3(a.x + b.x, a.y + b.y, a.z + b.z); +} +INLINE HOSTDEVICE void operator+=(int3& a, const int3& b) +{ + a.x += b.x; a.y += b.y; a.z += b.z; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE int3 operator-(const int3& a, const int3& b) +{ + return make_int3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +INLINE HOSTDEVICE void operator-=(int3& a, const int3& b) +{ + a.x -= b.x; a.y -= b.y; a.z -= b.z; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE int3 operator*(const int3& a, const int3& b) +{ + return make_int3(a.x * b.x, a.y * b.y, a.z * b.z); +} +INLINE HOSTDEVICE int3 operator*(const int3& a, const int s) +{ + return make_int3(a.x * s, a.y * s, a.z * s); +} +INLINE HOSTDEVICE int3 operator*(const int s, const int3& a) +{ + return make_int3(a.x * s, a.y * s, a.z * s); +} +INLINE HOSTDEVICE void operator*=(int3& a, const int s) +{ + a.x *= s; a.y *= s; a.z *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE int3 operator/(const int3& a, const int3& b) +{ + return make_int3(a.x / b.x, a.y / b.y, a.z / b.z); +} +INLINE HOSTDEVICE int3 operator/(const int3& a, const int s) +{ + return make_int3(a.x / s, a.y / s, a.z / s); +} +INLINE HOSTDEVICE int3 operator/(const int s, const int3& a) +{ + return make_int3(s /a.x, s / a.y, s / a.z); +} +INLINE HOSTDEVICE void operator/=(int3& a, const int s) +{ + a.x /= s; a.y /= s; a.z /= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE int3 clamp(const int3& v, const int a, const int b) +{ + return make_int3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b)); +} + +INLINE HOSTDEVICE int3 clamp(const int3& v, const int3& a, const int3& b) +{ + return make_int3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const int3& a, const int3& b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z; +} + +INLINE HOSTDEVICE bool operator!=(const int3& a, const int3& b) +{ + return a.x != b.x || a.y != b.y || a.z != b.z; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE int getByIndex(const int3& v, int i) +{ + return ((int*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(int3& v, int i, int x) +{ + ((int*)(&v))[i] = x; +} + + +/* int4 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE int4 make_int4(const int s) +{ + return make_int4(s, s, s, s); +} +INLINE HOSTDEVICE int4 make_int4(const float4& a) +{ + return make_int4((int)a.x, (int)a.y, (int)a.z, (int)a.w); +} +/** @} */ + +/** negate */ +INLINE HOSTDEVICE int4 operator-(const int4& a) +{ + return make_int4(-a.x, -a.y, -a.z, -a.w); +} + +/** min */ +INLINE HOSTDEVICE int4 min(const int4& a, const int4& b) +{ + return make_int4(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z), min(a.w,b.w)); +} + +/** max */ +INLINE HOSTDEVICE int4 max(const int4& a, const int4& b) +{ + return make_int4(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z), max(a.w,b.w)); +} + +/** add +* @{ +*/ +INLINE HOSTDEVICE int4 operator+(const int4& a, const int4& b) +{ + return make_int4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); +} +INLINE HOSTDEVICE void operator+=(int4& a, const int4& b) +{ + a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE int4 operator-(const int4& a, const int4& b) +{ + return make_int4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); +} + +INLINE HOSTDEVICE void operator-=(int4& a, const int4& b) +{ + a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE int4 operator*(const int4& a, const int4& b) +{ + return make_int4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); +} +INLINE HOSTDEVICE int4 operator*(const int4& a, const int s) +{ + return make_int4(a.x * s, a.y * s, a.z * s, a.w * s); +} +INLINE HOSTDEVICE int4 operator*(const int s, const int4& a) +{ + return make_int4(a.x * s, a.y * s, a.z * s, a.w * s); +} +INLINE HOSTDEVICE void operator*=(int4& a, const int s) +{ + a.x *= s; a.y *= s; a.z *= s; a.w *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE int4 operator/(const int4& a, const int4& b) +{ + return make_int4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); +} +INLINE HOSTDEVICE int4 operator/(const int4& a, const int s) +{ + return make_int4(a.x / s, a.y / s, a.z / s, a.w / s); +} +INLINE HOSTDEVICE int4 operator/(const int s, const int4& a) +{ + return make_int4(s / a.x, s / a.y, s / a.z, s / a.w); +} +INLINE HOSTDEVICE void operator/=(int4& a, const int s) +{ + a.x /= s; a.y /= s; a.z /= s; a.w /= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE int4 clamp(const int4& v, const int a, const int b) +{ + return make_int4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b)); +} + +INLINE HOSTDEVICE int4 clamp(const int4& v, const int4& a, const int4& b) +{ + return make_int4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const int4& a, const int4& b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; +} + +INLINE HOSTDEVICE bool operator!=(const int4& a, const int4& b) +{ + return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE int getByIndex(const int4& v, int i) +{ + return ((int*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(int4& v, int i, int x) +{ + ((int*)(&v))[i] = x; +} + + +/* uint functions */ +/******************************************************************************/ + +/** clamp */ +INLINE HOSTDEVICE unsigned int clamp(const unsigned int f, const unsigned int a, const unsigned int b) +{ + return max(a, min(f, b)); +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE unsigned int getByIndex(const uint1& v, unsigned int i) +{ + return ((unsigned int*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(uint1& v, int i, unsigned int x) +{ + ((unsigned int*)(&v))[i] = x; +} + + +/* uint2 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE uint2 make_uint2(const unsigned int s) +{ + return make_uint2(s, s); +} +INLINE HOSTDEVICE uint2 make_uint2(const float2& a) +{ + return make_uint2((unsigned int)a.x, (unsigned int)a.y); +} +/** @} */ + +/** min */ +INLINE HOSTDEVICE uint2 min(const uint2& a, const uint2& b) +{ + return make_uint2(min(a.x,b.x), min(a.y,b.y)); +} + +/** max */ +INLINE HOSTDEVICE uint2 max(const uint2& a, const uint2& b) +{ + return make_uint2(max(a.x,b.x), max(a.y,b.y)); +} + +/** add +* @{ +*/ +INLINE HOSTDEVICE uint2 operator+(const uint2& a, const uint2& b) +{ + return make_uint2(a.x + b.x, a.y + b.y); +} +INLINE HOSTDEVICE void operator+=(uint2& a, const uint2& b) +{ + a.x += b.x; a.y += b.y; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE uint2 operator-(const uint2& a, const uint2& b) +{ + return make_uint2(a.x - b.x, a.y - b.y); +} +INLINE HOSTDEVICE uint2 operator-(const uint2& a, const unsigned int b) +{ + return make_uint2(a.x - b, a.y - b); +} +INLINE HOSTDEVICE void operator-=(uint2& a, const uint2& b) +{ + a.x -= b.x; a.y -= b.y; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE uint2 operator*(const uint2& a, const uint2& b) +{ + return make_uint2(a.x * b.x, a.y * b.y); +} +INLINE HOSTDEVICE uint2 operator*(const uint2& a, const unsigned int s) +{ + return make_uint2(a.x * s, a.y * s); +} +INLINE HOSTDEVICE uint2 operator*(const unsigned int s, const uint2& a) +{ + return make_uint2(a.x * s, a.y * s); +} +INLINE HOSTDEVICE void operator*=(uint2& a, const unsigned int s) +{ + a.x *= s; a.y *= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE uint2 clamp(const uint2& v, const unsigned int a, const unsigned int b) +{ + return make_uint2(clamp(v.x, a, b), clamp(v.y, a, b)); +} + +INLINE HOSTDEVICE uint2 clamp(const uint2& v, const uint2& a, const uint2& b) +{ + return make_uint2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const uint2& a, const uint2& b) +{ + return a.x == b.x && a.y == b.y; +} + +INLINE HOSTDEVICE bool operator!=(const uint2& a, const uint2& b) +{ + return a.x != b.x || a.y != b.y; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE unsigned int getByIndex(const uint2& v, unsigned int i) +{ + return ((unsigned int*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(uint2& v, int i, unsigned int x) +{ + ((unsigned int*)(&v))[i] = x; +} + + +/* uint3 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE uint3 make_uint3(const unsigned int s) +{ + return make_uint3(s, s, s); +} +INLINE HOSTDEVICE uint3 make_uint3(const float3& a) +{ + return make_uint3((unsigned int)a.x, (unsigned int)a.y, (unsigned int)a.z); +} +/** @} */ + +/** min */ +INLINE HOSTDEVICE uint3 min(const uint3& a, const uint3& b) +{ + return make_uint3(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z)); +} + +/** max */ +INLINE HOSTDEVICE uint3 max(const uint3& a, const uint3& b) +{ + return make_uint3(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z)); +} + +/** add +* @{ +*/ +INLINE HOSTDEVICE uint3 operator+(const uint3& a, const uint3& b) +{ + return make_uint3(a.x + b.x, a.y + b.y, a.z + b.z); +} +INLINE HOSTDEVICE void operator+=(uint3& a, const uint3& b) +{ + a.x += b.x; a.y += b.y; a.z += b.z; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE uint3 operator-(const uint3& a, const uint3& b) +{ + return make_uint3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +INLINE HOSTDEVICE void operator-=(uint3& a, const uint3& b) +{ + a.x -= b.x; a.y -= b.y; a.z -= b.z; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE uint3 operator*(const uint3& a, const uint3& b) +{ + return make_uint3(a.x * b.x, a.y * b.y, a.z * b.z); +} +INLINE HOSTDEVICE uint3 operator*(const uint3& a, const unsigned int s) +{ + return make_uint3(a.x * s, a.y * s, a.z * s); +} +INLINE HOSTDEVICE uint3 operator*(const unsigned int s, const uint3& a) +{ + return make_uint3(a.x * s, a.y * s, a.z * s); +} +INLINE HOSTDEVICE void operator*=(uint3& a, const unsigned int s) +{ + a.x *= s; a.y *= s; a.z *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE uint3 operator/(const uint3& a, const uint3& b) +{ + return make_uint3(a.x / b.x, a.y / b.y, a.z / b.z); +} +INLINE HOSTDEVICE uint3 operator/(const uint3& a, const unsigned int s) +{ + return make_uint3(a.x / s, a.y / s, a.z / s); +} +INLINE HOSTDEVICE uint3 operator/(const unsigned int s, const uint3& a) +{ + return make_uint3(s / a.x, s / a.y, s / a.z); +} +INLINE HOSTDEVICE void operator/=(uint3& a, const unsigned int s) +{ + a.x /= s; a.y /= s; a.z /= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE uint3 clamp(const uint3& v, const unsigned int a, const unsigned int b) +{ + return make_uint3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b)); +} + +INLINE HOSTDEVICE uint3 clamp(const uint3& v, const uint3& a, const uint3& b) +{ + return make_uint3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const uint3& a, const uint3& b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z; +} + +INLINE HOSTDEVICE bool operator!=(const uint3& a, const uint3& b) +{ + return a.x != b.x || a.y != b.y || a.z != b.z; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory +*/ +INLINE HOSTDEVICE unsigned int getByIndex(const uint3& v, unsigned int i) +{ + return ((unsigned int*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory +*/ +INLINE HOSTDEVICE void setByIndex(uint3& v, int i, unsigned int x) +{ + ((unsigned int*)(&v))[i] = x; +} + + +/* uint4 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE uint4 make_uint4(const unsigned int s) +{ + return make_uint4(s, s, s, s); +} +INLINE HOSTDEVICE uint4 make_uint4(const float4& a) +{ + return make_uint4((unsigned int)a.x, (unsigned int)a.y, (unsigned int)a.z, (unsigned int)a.w); +} +/** @} */ + +/** min +* @{ +*/ +INLINE HOSTDEVICE uint4 min(const uint4& a, const uint4& b) +{ + return make_uint4(min(a.x,b.x), min(a.y,b.y), min(a.z,b.z), min(a.w,b.w)); +} +/** @} */ + +/** max +* @{ +*/ +INLINE HOSTDEVICE uint4 max(const uint4& a, const uint4& b) +{ + return make_uint4(max(a.x,b.x), max(a.y,b.y), max(a.z,b.z), max(a.w,b.w)); +} +/** @} */ + +/** add +* @{ +*/ +INLINE HOSTDEVICE uint4 operator+(const uint4& a, const uint4& b) +{ + return make_uint4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); +} +INLINE HOSTDEVICE void operator+=(uint4& a, const uint4& b) +{ + a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE uint4 operator-(const uint4& a, const uint4& b) +{ + return make_uint4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); +} + +INLINE HOSTDEVICE void operator-=(uint4& a, const uint4& b) +{ + a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE uint4 operator*(const uint4& a, const uint4& b) +{ + return make_uint4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); +} +INLINE HOSTDEVICE uint4 operator*(const uint4& a, const unsigned int s) +{ + return make_uint4(a.x * s, a.y * s, a.z * s, a.w * s); +} +INLINE HOSTDEVICE uint4 operator*(const unsigned int s, const uint4& a) +{ + return make_uint4(a.x * s, a.y * s, a.z * s, a.w * s); +} +INLINE HOSTDEVICE void operator*=(uint4& a, const unsigned int s) +{ + a.x *= s; a.y *= s; a.z *= s; a.w *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE uint4 operator/(const uint4& a, const uint4& b) +{ + return make_uint4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); +} +INLINE HOSTDEVICE uint4 operator/(const uint4& a, const unsigned int s) +{ + return make_uint4(a.x / s, a.y / s, a.z / s, a.w / s); +} +INLINE HOSTDEVICE uint4 operator/(const unsigned int s, const uint4& a) +{ + return make_uint4(s / a.x, s / a.y, s / a.z, s / a.w); +} +INLINE HOSTDEVICE void operator/=(uint4& a, const unsigned int s) +{ + a.x /= s; a.y /= s; a.z /= s; a.w /= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE uint4 clamp(const uint4& v, const unsigned int a, const unsigned int b) +{ + return make_uint4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b)); +} + +INLINE HOSTDEVICE uint4 clamp(const uint4& v, const uint4& a, const uint4& b) +{ + return make_uint4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const uint4& a, const uint4& b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; +} + +INLINE HOSTDEVICE bool operator!=(const uint4& a, const uint4& b) +{ + return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory +*/ +INLINE HOSTDEVICE unsigned int getByIndex(const uint4& v, unsigned int i) +{ + return ((unsigned int*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory +*/ +INLINE HOSTDEVICE void setByIndex(uint4& v, int i, unsigned int x) +{ + ((unsigned int*)(&v))[i] = x; +} + +/* long long functions */ +/******************************************************************************/ + +/** clamp */ +INLINE HOSTDEVICE long long clamp(const long long f, const long long a, const long long b) +{ + return max(a, min(f, b)); +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE long long getByIndex(const longlong1& v, int i) +{ + return ((long long*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(longlong1& v, int i, long long x) +{ + ((long long*)(&v))[i] = x; +} + + +/* longlong2 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE longlong2 make_longlong2(const long long s) +{ + return make_longlong2(s, s); +} +INLINE HOSTDEVICE longlong2 make_longlong2(const float2& a) +{ + return make_longlong2(int(a.x), int(a.y)); +} +/** @} */ + +/** negate */ +INLINE HOSTDEVICE longlong2 operator-(const longlong2& a) +{ + return make_longlong2(-a.x, -a.y); +} + +/** min */ +INLINE HOSTDEVICE longlong2 min(const longlong2& a, const longlong2& b) +{ + return make_longlong2(min(a.x, b.x), min(a.y, b.y)); +} + +/** max */ +INLINE HOSTDEVICE longlong2 max(const longlong2& a, const longlong2& b) +{ + return make_longlong2(max(a.x, b.x), max(a.y, b.y)); +} + +/** add +* @{ +*/ +INLINE HOSTDEVICE longlong2 operator+(const longlong2& a, const longlong2& b) +{ + return make_longlong2(a.x + b.x, a.y + b.y); +} +INLINE HOSTDEVICE void operator+=(longlong2& a, const longlong2& b) +{ + a.x += b.x; a.y += b.y; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE longlong2 operator-(const longlong2& a, const longlong2& b) +{ + return make_longlong2(a.x - b.x, a.y - b.y); +} +INLINE HOSTDEVICE longlong2 operator-(const longlong2& a, const long long b) +{ + return make_longlong2(a.x - b, a.y - b); +} +INLINE HOSTDEVICE void operator-=(longlong2& a, const longlong2& b) +{ + a.x -= b.x; a.y -= b.y; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE longlong2 operator*(const longlong2& a, const longlong2& b) +{ + return make_longlong2(a.x * b.x, a.y * b.y); +} +INLINE HOSTDEVICE longlong2 operator*(const longlong2& a, const long long s) +{ + return make_longlong2(a.x * s, a.y * s); +} +INLINE HOSTDEVICE longlong2 operator*(const long long s, const longlong2& a) +{ + return make_longlong2(a.x * s, a.y * s); +} +INLINE HOSTDEVICE void operator*=(longlong2& a, const long long s) +{ + a.x *= s; a.y *= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE longlong2 clamp(const longlong2& v, const long long a, const long long b) +{ + return make_longlong2(clamp(v.x, a, b), clamp(v.y, a, b)); +} + +INLINE HOSTDEVICE longlong2 clamp(const longlong2& v, const longlong2& a, const longlong2& b) +{ + return make_longlong2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const longlong2& a, const longlong2& b) +{ + return a.x == b.x && a.y == b.y; +} + +INLINE HOSTDEVICE bool operator!=(const longlong2& a, const longlong2& b) +{ + return a.x != b.x || a.y != b.y; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE long long getByIndex(const longlong2& v, int i) +{ + return ((long long*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(longlong2& v, int i, long long x) +{ + ((long long*)(&v))[i] = x; +} + + +/* longlong3 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE longlong3 make_longlong3(const long long s) +{ + return make_longlong3(s, s, s); +} +INLINE HOSTDEVICE longlong3 make_longlong3(const float3& a) +{ + return make_longlong3( (long long)a.x, (long long)a.y, (long long)a.z); +} +/** @} */ + +/** negate */ +INLINE HOSTDEVICE longlong3 operator-(const longlong3& a) +{ + return make_longlong3(-a.x, -a.y, -a.z); +} + +/** min */ +INLINE HOSTDEVICE longlong3 min(const longlong3& a, const longlong3& b) +{ + return make_longlong3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)); +} + +/** max */ +INLINE HOSTDEVICE longlong3 max(const longlong3& a, const longlong3& b) +{ + return make_longlong3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)); +} + +/** add +* @{ +*/ +INLINE HOSTDEVICE longlong3 operator+(const longlong3& a, const longlong3& b) +{ + return make_longlong3(a.x + b.x, a.y + b.y, a.z + b.z); +} +INLINE HOSTDEVICE void operator+=(longlong3& a, const longlong3& b) +{ + a.x += b.x; a.y += b.y; a.z += b.z; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE longlong3 operator-(const longlong3& a, const longlong3& b) +{ + return make_longlong3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +INLINE HOSTDEVICE void operator-=(longlong3& a, const longlong3& b) +{ + a.x -= b.x; a.y -= b.y; a.z -= b.z; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE longlong3 operator*(const longlong3& a, const longlong3& b) +{ + return make_longlong3(a.x * b.x, a.y * b.y, a.z * b.z); +} +INLINE HOSTDEVICE longlong3 operator*(const longlong3& a, const long long s) +{ + return make_longlong3(a.x * s, a.y * s, a.z * s); +} +INLINE HOSTDEVICE longlong3 operator*(const long long s, const longlong3& a) +{ + return make_longlong3(a.x * s, a.y * s, a.z * s); +} +INLINE HOSTDEVICE void operator*=(longlong3& a, const long long s) +{ + a.x *= s; a.y *= s; a.z *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE longlong3 operator/(const longlong3& a, const longlong3& b) +{ + return make_longlong3(a.x / b.x, a.y / b.y, a.z / b.z); +} +INLINE HOSTDEVICE longlong3 operator/(const longlong3& a, const long long s) +{ + return make_longlong3(a.x / s, a.y / s, a.z / s); +} +INLINE HOSTDEVICE longlong3 operator/(const long long s, const longlong3& a) +{ + return make_longlong3(s /a.x, s / a.y, s / a.z); +} +INLINE HOSTDEVICE void operator/=(longlong3& a, const long long s) +{ + a.x /= s; a.y /= s; a.z /= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE longlong3 clamp(const longlong3& v, const long long a, const long long b) +{ + return make_longlong3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b)); +} + +INLINE HOSTDEVICE longlong3 clamp(const longlong3& v, const longlong3& a, const longlong3& b) +{ + return make_longlong3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const longlong3& a, const longlong3& b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z; +} + +INLINE HOSTDEVICE bool operator!=(const longlong3& a, const longlong3& b) +{ + return a.x != b.x || a.y != b.y || a.z != b.z; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE long long getByIndex(const longlong3& v, int i) +{ + return ((long long*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(longlong3& v, int i, int x) +{ + ((long long*)(&v))[i] = x; +} + + +/* longlong4 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE longlong4 make_longlong4(const long long s) +{ + return make_longlong4(s, s, s, s); +} +INLINE HOSTDEVICE longlong4 make_longlong4(const float4& a) +{ + return make_longlong4((long long)a.x, (long long)a.y, (long long)a.z, (long long)a.w); +} +/** @} */ + +/** negate */ +INLINE HOSTDEVICE longlong4 operator-(const longlong4& a) +{ + return make_longlong4(-a.x, -a.y, -a.z, -a.w); +} + +/** min */ +INLINE HOSTDEVICE longlong4 min(const longlong4& a, const longlong4& b) +{ + return make_longlong4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); +} + +/** max */ +INLINE HOSTDEVICE longlong4 max(const longlong4& a, const longlong4& b) +{ + return make_longlong4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); +} + +/** add +* @{ +*/ +INLINE HOSTDEVICE longlong4 operator+(const longlong4& a, const longlong4& b) +{ + return make_longlong4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); +} +INLINE HOSTDEVICE void operator+=(longlong4& a, const longlong4& b) +{ + a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE longlong4 operator-(const longlong4& a, const longlong4& b) +{ + return make_longlong4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); +} + +INLINE HOSTDEVICE void operator-=(longlong4& a, const longlong4& b) +{ + a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE longlong4 operator*(const longlong4& a, const longlong4& b) +{ + return make_longlong4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); +} +INLINE HOSTDEVICE longlong4 operator*(const longlong4& a, const long long s) +{ + return make_longlong4(a.x * s, a.y * s, a.z * s, a.w * s); +} +INLINE HOSTDEVICE longlong4 operator*(const long long s, const longlong4& a) +{ + return make_longlong4(a.x * s, a.y * s, a.z * s, a.w * s); +} +INLINE HOSTDEVICE void operator*=(longlong4& a, const long long s) +{ + a.x *= s; a.y *= s; a.z *= s; a.w *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE longlong4 operator/(const longlong4& a, const longlong4& b) +{ + return make_longlong4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); +} +INLINE HOSTDEVICE longlong4 operator/(const longlong4& a, const long long s) +{ + return make_longlong4(a.x / s, a.y / s, a.z / s, a.w / s); +} +INLINE HOSTDEVICE longlong4 operator/(const long long s, const longlong4& a) +{ + return make_longlong4(s / a.x, s / a.y, s / a.z, s / a.w); +} +INLINE HOSTDEVICE void operator/=(longlong4& a, const long long s) +{ + a.x /= s; a.y /= s; a.z /= s; a.w /= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE longlong4 clamp(const longlong4& v, const long long a, const long long b) +{ + return make_longlong4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b)); +} + +INLINE HOSTDEVICE longlong4 clamp(const longlong4& v, const longlong4& a, const longlong4& b) +{ + return make_longlong4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const longlong4& a, const longlong4& b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; +} + +INLINE HOSTDEVICE bool operator!=(const longlong4& a, const longlong4& b) +{ + return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE long long getByIndex(const longlong4& v, int i) +{ + return ((long long*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(longlong4& v, int i, long long x) +{ + ((long long*)(&v))[i] = x; +} + +/* ulonglong functions */ +/******************************************************************************/ + +/** clamp */ +INLINE HOSTDEVICE unsigned long long clamp(const unsigned long long f, const unsigned long long a, const unsigned long long b) +{ + return max(a, min(f, b)); +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE unsigned long long getByIndex(const ulonglong1& v, unsigned int i) +{ + return ((unsigned long long*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(ulonglong1& v, int i, unsigned long long x) +{ + ((unsigned long long*)(&v))[i] = x; +} + + +/* ulonglong2 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE ulonglong2 make_ulonglong2(const unsigned long long s) +{ + return make_ulonglong2(s, s); +} +INLINE HOSTDEVICE ulonglong2 make_ulonglong2(const float2& a) +{ + return make_ulonglong2((unsigned long long)a.x, (unsigned long long)a.y); +} +/** @} */ + +/** min */ +INLINE HOSTDEVICE ulonglong2 min(const ulonglong2& a, const ulonglong2& b) +{ + return make_ulonglong2(min(a.x, b.x), min(a.y, b.y)); +} + +/** max */ +INLINE HOSTDEVICE ulonglong2 max(const ulonglong2& a, const ulonglong2& b) +{ + return make_ulonglong2(max(a.x, b.x), max(a.y, b.y)); +} + +/** add +* @{ +*/ +INLINE HOSTDEVICE ulonglong2 operator+(const ulonglong2& a, const ulonglong2& b) +{ + return make_ulonglong2(a.x + b.x, a.y + b.y); +} +INLINE HOSTDEVICE void operator+=(ulonglong2& a, const ulonglong2& b) +{ + a.x += b.x; a.y += b.y; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE ulonglong2 operator-(const ulonglong2& a, const ulonglong2& b) +{ + return make_ulonglong2(a.x - b.x, a.y - b.y); +} +INLINE HOSTDEVICE ulonglong2 operator-(const ulonglong2& a, const unsigned long long b) +{ + return make_ulonglong2(a.x - b, a.y - b); +} +INLINE HOSTDEVICE void operator-=(ulonglong2& a, const ulonglong2& b) +{ + a.x -= b.x; a.y -= b.y; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE ulonglong2 operator*(const ulonglong2& a, const ulonglong2& b) +{ + return make_ulonglong2(a.x * b.x, a.y * b.y); +} +INLINE HOSTDEVICE ulonglong2 operator*(const ulonglong2& a, const unsigned long long s) +{ + return make_ulonglong2(a.x * s, a.y * s); +} +INLINE HOSTDEVICE ulonglong2 operator*(const unsigned long long s, const ulonglong2& a) +{ + return make_ulonglong2(a.x * s, a.y * s); +} +INLINE HOSTDEVICE void operator*=(ulonglong2& a, const unsigned long long s) +{ + a.x *= s; a.y *= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE ulonglong2 clamp(const ulonglong2& v, const unsigned long long a, const unsigned long long b) +{ + return make_ulonglong2(clamp(v.x, a, b), clamp(v.y, a, b)); +} + +INLINE HOSTDEVICE ulonglong2 clamp(const ulonglong2& v, const ulonglong2& a, const ulonglong2& b) +{ + return make_ulonglong2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const ulonglong2& a, const ulonglong2& b) +{ + return a.x == b.x && a.y == b.y; +} + +INLINE HOSTDEVICE bool operator!=(const ulonglong2& a, const ulonglong2& b) +{ + return a.x != b.x || a.y != b.y; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE unsigned long long getByIndex(const ulonglong2& v, unsigned int i) +{ + return ((unsigned long long*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory */ +INLINE HOSTDEVICE void setByIndex(ulonglong2& v, int i, unsigned long long x) +{ + ((unsigned long long*)(&v))[i] = x; +} + + +/* ulonglong3 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE ulonglong3 make_ulonglong3(const unsigned long long s) +{ + return make_ulonglong3(s, s, s); +} +INLINE HOSTDEVICE ulonglong3 make_ulonglong3(const float3& a) +{ + return make_ulonglong3((unsigned long long)a.x, (unsigned long long)a.y, (unsigned long long)a.z); +} +/** @} */ + +/** min */ +INLINE HOSTDEVICE ulonglong3 min(const ulonglong3& a, const ulonglong3& b) +{ + return make_ulonglong3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)); +} + +/** max */ +INLINE HOSTDEVICE ulonglong3 max(const ulonglong3& a, const ulonglong3& b) +{ + return make_ulonglong3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)); +} + +/** add +* @{ +*/ +INLINE HOSTDEVICE ulonglong3 operator+(const ulonglong3& a, const ulonglong3& b) +{ + return make_ulonglong3(a.x + b.x, a.y + b.y, a.z + b.z); +} +INLINE HOSTDEVICE void operator+=(ulonglong3& a, const ulonglong3& b) +{ + a.x += b.x; a.y += b.y; a.z += b.z; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE ulonglong3 operator-(const ulonglong3& a, const ulonglong3& b) +{ + return make_ulonglong3(a.x - b.x, a.y - b.y, a.z - b.z); +} + +INLINE HOSTDEVICE void operator-=(ulonglong3& a, const ulonglong3& b) +{ + a.x -= b.x; a.y -= b.y; a.z -= b.z; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE ulonglong3 operator*(const ulonglong3& a, const ulonglong3& b) +{ + return make_ulonglong3(a.x * b.x, a.y * b.y, a.z * b.z); +} +INLINE HOSTDEVICE ulonglong3 operator*(const ulonglong3& a, const unsigned long long s) +{ + return make_ulonglong3(a.x * s, a.y * s, a.z * s); +} +INLINE HOSTDEVICE ulonglong3 operator*(const unsigned long long s, const ulonglong3& a) +{ + return make_ulonglong3(a.x * s, a.y * s, a.z * s); +} +INLINE HOSTDEVICE void operator*=(ulonglong3& a, const unsigned long long s) +{ + a.x *= s; a.y *= s; a.z *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE ulonglong3 operator/(const ulonglong3& a, const ulonglong3& b) +{ + return make_ulonglong3(a.x / b.x, a.y / b.y, a.z / b.z); +} +INLINE HOSTDEVICE ulonglong3 operator/(const ulonglong3& a, const unsigned long long s) +{ + return make_ulonglong3(a.x / s, a.y / s, a.z / s); +} +INLINE HOSTDEVICE ulonglong3 operator/(const unsigned long long s, const ulonglong3& a) +{ + return make_ulonglong3(s / a.x, s / a.y, s / a.z); +} +INLINE HOSTDEVICE void operator/=(ulonglong3& a, const unsigned long long s) +{ + a.x /= s; a.y /= s; a.z /= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE ulonglong3 clamp(const ulonglong3& v, const unsigned long long a, const unsigned long long b) +{ + return make_ulonglong3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b)); +} + +INLINE HOSTDEVICE ulonglong3 clamp(const ulonglong3& v, const ulonglong3& a, const ulonglong3& b) +{ + return make_ulonglong3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const ulonglong3& a, const ulonglong3& b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z; +} + +INLINE HOSTDEVICE bool operator!=(const ulonglong3& a, const ulonglong3& b) +{ + return a.x != b.x || a.y != b.y || a.z != b.z; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory +*/ +INLINE HOSTDEVICE unsigned long long getByIndex(const ulonglong3& v, unsigned int i) +{ + return ((unsigned long long*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory +*/ +INLINE HOSTDEVICE void setByIndex(ulonglong3& v, int i, unsigned long long x) +{ + ((unsigned long long*)(&v))[i] = x; +} + + +/* ulonglong4 functions */ +/******************************************************************************/ + +/** additional constructors +* @{ +*/ +INLINE HOSTDEVICE ulonglong4 make_ulonglong4(const unsigned long long s) +{ + return make_ulonglong4(s, s, s, s); +} +INLINE HOSTDEVICE ulonglong4 make_ulonglong4(const float4& a) +{ + return make_ulonglong4((unsigned long long)a.x, (unsigned long long)a.y, (unsigned long long)a.z, (unsigned long long)a.w); +} +/** @} */ + +/** min +* @{ +*/ +INLINE HOSTDEVICE ulonglong4 min(const ulonglong4& a, const ulonglong4& b) +{ + return make_ulonglong4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); +} +/** @} */ + +/** max +* @{ +*/ +INLINE HOSTDEVICE ulonglong4 max(const ulonglong4& a, const ulonglong4& b) +{ + return make_ulonglong4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); +} +/** @} */ + +/** add +* @{ +*/ +INLINE HOSTDEVICE ulonglong4 operator+(const ulonglong4& a, const ulonglong4& b) +{ + return make_ulonglong4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); +} +INLINE HOSTDEVICE void operator+=(ulonglong4& a, const ulonglong4& b) +{ + a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; +} +/** @} */ + +/** subtract +* @{ +*/ +INLINE HOSTDEVICE ulonglong4 operator-(const ulonglong4& a, const ulonglong4& b) +{ + return make_ulonglong4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); +} + +INLINE HOSTDEVICE void operator-=(ulonglong4& a, const ulonglong4& b) +{ + a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; +} +/** @} */ + +/** multiply +* @{ +*/ +INLINE HOSTDEVICE ulonglong4 operator*(const ulonglong4& a, const ulonglong4& b) +{ + return make_ulonglong4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); +} +INLINE HOSTDEVICE ulonglong4 operator*(const ulonglong4& a, const unsigned long long s) +{ + return make_ulonglong4(a.x * s, a.y * s, a.z * s, a.w * s); +} +INLINE HOSTDEVICE ulonglong4 operator*(const unsigned long long s, const ulonglong4& a) +{ + return make_ulonglong4(a.x * s, a.y * s, a.z * s, a.w * s); +} +INLINE HOSTDEVICE void operator*=(ulonglong4& a, const unsigned long long s) +{ + a.x *= s; a.y *= s; a.z *= s; a.w *= s; +} +/** @} */ + +/** divide +* @{ +*/ +INLINE HOSTDEVICE ulonglong4 operator/(const ulonglong4& a, const ulonglong4& b) +{ + return make_ulonglong4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); +} +INLINE HOSTDEVICE ulonglong4 operator/(const ulonglong4& a, const unsigned long long s) +{ + return make_ulonglong4(a.x / s, a.y / s, a.z / s, a.w / s); +} +INLINE HOSTDEVICE ulonglong4 operator/(const unsigned long long s, const ulonglong4& a) +{ + return make_ulonglong4(s / a.x, s / a.y, s / a.z, s / a.w); +} +INLINE HOSTDEVICE void operator/=(ulonglong4& a, const unsigned long long s) +{ + a.x /= s; a.y /= s; a.z /= s; a.w /= s; +} +/** @} */ + +/** clamp +* @{ +*/ +INLINE HOSTDEVICE ulonglong4 clamp(const ulonglong4& v, const unsigned long long a, const unsigned long long b) +{ + return make_ulonglong4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b)); +} + +INLINE HOSTDEVICE ulonglong4 clamp(const ulonglong4& v, const ulonglong4& a, const ulonglong4& b) +{ + return make_ulonglong4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w)); +} +/** @} */ + +/** equality +* @{ +*/ +INLINE HOSTDEVICE bool operator==(const ulonglong4& a, const ulonglong4& b) +{ + return a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w; +} + +INLINE HOSTDEVICE bool operator!=(const ulonglong4& a, const ulonglong4& b) +{ + return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; +} +/** @} */ + +/** If used on the device, this could place the the 'v' in local memory +*/ +INLINE HOSTDEVICE unsigned long long getByIndex(const ulonglong4& v, unsigned int i) +{ + return ((unsigned long long*)(&v))[i]; +} + +/** If used on the device, this could place the the 'v' in local memory +*/ +INLINE HOSTDEVICE void setByIndex(ulonglong4& v, int i, unsigned long long x) +{ + ((unsigned long long*)(&v))[i] = x; +} + + +/******************************************************************************/ + +/** Narrowing functions +* @{ +*/ +INLINE HOSTDEVICE int2 make_int2(const int3& v0) { return make_int2( v0.x, v0.y ); } +INLINE HOSTDEVICE int2 make_int2(const int4& v0) { return make_int2( v0.x, v0.y ); } +INLINE HOSTDEVICE int3 make_int3(const int4& v0) { return make_int3( v0.x, v0.y, v0.z ); } +INLINE HOSTDEVICE uint2 make_uint2(const uint3& v0) { return make_uint2( v0.x, v0.y ); } +INLINE HOSTDEVICE uint2 make_uint2(const uint4& v0) { return make_uint2( v0.x, v0.y ); } +INLINE HOSTDEVICE uint3 make_uint3(const uint4& v0) { return make_uint3( v0.x, v0.y, v0.z ); } +INLINE HOSTDEVICE longlong2 make_longlong2(const longlong3& v0) { return make_longlong2( v0.x, v0.y ); } +INLINE HOSTDEVICE longlong2 make_longlong2(const longlong4& v0) { return make_longlong2( v0.x, v0.y ); } +INLINE HOSTDEVICE longlong3 make_longlong3(const longlong4& v0) { return make_longlong3( v0.x, v0.y, v0.z ); } +INLINE HOSTDEVICE ulonglong2 make_ulonglong2(const ulonglong3& v0) { return make_ulonglong2( v0.x, v0.y ); } +INLINE HOSTDEVICE ulonglong2 make_ulonglong2(const ulonglong4& v0) { return make_ulonglong2( v0.x, v0.y ); } +INLINE HOSTDEVICE ulonglong3 make_ulonglong3(const ulonglong4& v0) { return make_ulonglong3( v0.x, v0.y, v0.z ); } +INLINE HOSTDEVICE float2 make_float2(const float3& v0) { return make_float2( v0.x, v0.y ); } +INLINE HOSTDEVICE float2 make_float2(const float4& v0) { return make_float2( v0.x, v0.y ); } +INLINE HOSTDEVICE float3 make_float3(const float4& v0) { return make_float3( v0.x, v0.y, v0.z ); } +/** @} */ + +/** Assemble functions from smaller vectors +* @{ +*/ +INLINE HOSTDEVICE int3 make_int3(const int v0, const int2& v1) { return make_int3( v0, v1.x, v1.y ); } +INLINE HOSTDEVICE int3 make_int3(const int2& v0, const int v1) { return make_int3( v0.x, v0.y, v1 ); } +INLINE HOSTDEVICE int4 make_int4(const int v0, const int v1, const int2& v2) { return make_int4( v0, v1, v2.x, v2.y ); } +INLINE HOSTDEVICE int4 make_int4(const int v0, const int2& v1, const int v2) { return make_int4( v0, v1.x, v1.y, v2 ); } +INLINE HOSTDEVICE int4 make_int4(const int2& v0, const int v1, const int v2) { return make_int4( v0.x, v0.y, v1, v2 ); } +INLINE HOSTDEVICE int4 make_int4(const int v0, const int3& v1) { return make_int4( v0, v1.x, v1.y, v1.z ); } +INLINE HOSTDEVICE int4 make_int4(const int3& v0, const int v1) { return make_int4( v0.x, v0.y, v0.z, v1 ); } +INLINE HOSTDEVICE int4 make_int4(const int2& v0, const int2& v1) { return make_int4( v0.x, v0.y, v1.x, v1.y ); } +INLINE HOSTDEVICE uint3 make_uint3(const unsigned int v0, const uint2& v1) { return make_uint3( v0, v1.x, v1.y ); } +INLINE HOSTDEVICE uint3 make_uint3(const uint2& v0, const unsigned int v1) { return make_uint3( v0.x, v0.y, v1 ); } +INLINE HOSTDEVICE uint4 make_uint4(const unsigned int v0, const unsigned int v1, const uint2& v2) { return make_uint4( v0, v1, v2.x, v2.y ); } +INLINE HOSTDEVICE uint4 make_uint4(const unsigned int v0, const uint2& v1, const unsigned int v2) { return make_uint4( v0, v1.x, v1.y, v2 ); } +INLINE HOSTDEVICE uint4 make_uint4(const uint2& v0, const unsigned int v1, const unsigned int v2) { return make_uint4( v0.x, v0.y, v1, v2 ); } +INLINE HOSTDEVICE uint4 make_uint4(const unsigned int v0, const uint3& v1) { return make_uint4( v0, v1.x, v1.y, v1.z ); } +INLINE HOSTDEVICE uint4 make_uint4(const uint3& v0, const unsigned int v1) { return make_uint4( v0.x, v0.y, v0.z, v1 ); } +INLINE HOSTDEVICE uint4 make_uint4(const uint2& v0, const uint2& v1) { return make_uint4( v0.x, v0.y, v1.x, v1.y ); } +INLINE HOSTDEVICE longlong3 make_longlong3(const long long v0, const longlong2& v1) { return make_longlong3(v0, v1.x, v1.y); } +INLINE HOSTDEVICE longlong3 make_longlong3(const longlong2& v0, const long long v1) { return make_longlong3(v0.x, v0.y, v1); } +INLINE HOSTDEVICE longlong4 make_longlong4(const long long v0, const long long v1, const longlong2& v2) { return make_longlong4(v0, v1, v2.x, v2.y); } +INLINE HOSTDEVICE longlong4 make_longlong4(const long long v0, const longlong2& v1, const long long v2) { return make_longlong4(v0, v1.x, v1.y, v2); } +INLINE HOSTDEVICE longlong4 make_longlong4(const longlong2& v0, const long long v1, const long long v2) { return make_longlong4(v0.x, v0.y, v1, v2); } +INLINE HOSTDEVICE longlong4 make_longlong4(const long long v0, const longlong3& v1) { return make_longlong4(v0, v1.x, v1.y, v1.z); } +INLINE HOSTDEVICE longlong4 make_longlong4(const longlong3& v0, const long long v1) { return make_longlong4(v0.x, v0.y, v0.z, v1); } +INLINE HOSTDEVICE longlong4 make_longlong4(const longlong2& v0, const longlong2& v1) { return make_longlong4(v0.x, v0.y, v1.x, v1.y); } +INLINE HOSTDEVICE ulonglong3 make_ulonglong3(const unsigned long long v0, const ulonglong2& v1) { return make_ulonglong3(v0, v1.x, v1.y); } +INLINE HOSTDEVICE ulonglong3 make_ulonglong3(const ulonglong2& v0, const unsigned long long v1) { return make_ulonglong3(v0.x, v0.y, v1); } +INLINE HOSTDEVICE ulonglong4 make_ulonglong4(const unsigned long long v0, const unsigned long long v1, const ulonglong2& v2) { return make_ulonglong4(v0, v1, v2.x, v2.y); } +INLINE HOSTDEVICE ulonglong4 make_ulonglong4(const unsigned long long v0, const ulonglong2& v1, const unsigned long long v2) { return make_ulonglong4(v0, v1.x, v1.y, v2); } +INLINE HOSTDEVICE ulonglong4 make_ulonglong4(const ulonglong2& v0, const unsigned long long v1, const unsigned long long v2) { return make_ulonglong4(v0.x, v0.y, v1, v2); } +INLINE HOSTDEVICE ulonglong4 make_ulonglong4(const unsigned long long v0, const ulonglong3& v1) { return make_ulonglong4(v0, v1.x, v1.y, v1.z); } +INLINE HOSTDEVICE ulonglong4 make_ulonglong4(const ulonglong3& v0, const unsigned long long v1) { return make_ulonglong4(v0.x, v0.y, v0.z, v1); } +INLINE HOSTDEVICE ulonglong4 make_ulonglong4(const ulonglong2& v0, const ulonglong2& v1) { return make_ulonglong4(v0.x, v0.y, v1.x, v1.y); } +INLINE HOSTDEVICE float3 make_float3(const float2& v0, const float v1) { return make_float3(v0.x, v0.y, v1); } +INLINE HOSTDEVICE float3 make_float3(const float v0, const float2& v1) { return make_float3( v0, v1.x, v1.y ); } +INLINE HOSTDEVICE float4 make_float4(const float v0, const float v1, const float2& v2) { return make_float4( v0, v1, v2.x, v2.y ); } +INLINE HOSTDEVICE float4 make_float4(const float v0, const float2& v1, const float v2) { return make_float4( v0, v1.x, v1.y, v2 ); } +INLINE HOSTDEVICE float4 make_float4(const float2& v0, const float v1, const float v2) { return make_float4( v0.x, v0.y, v1, v2 ); } +INLINE HOSTDEVICE float4 make_float4(const float v0, const float3& v1) { return make_float4( v0, v1.x, v1.y, v1.z ); } +INLINE HOSTDEVICE float4 make_float4(const float3& v0, const float v1) { return make_float4( v0.x, v0.y, v0.z, v1 ); } +INLINE HOSTDEVICE float4 make_float4(const float2& v0, const float2& v1) { return make_float4( v0.x, v0.y, v1.x, v1.y ); } +/** @} */ + + diff --git a/Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/model.py b/Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/model.py new file mode 100644 index 0000000000..cf5d6c47b7 --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/model.py @@ -0,0 +1,949 @@ +from __future__ import annotations + +import dataclasses +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Dict, List, Optional, Tuple, Literal +import os + +import torch +from nerfstudio.cameras.rays import RayBundle, RaySamples +from nerfstudio.field_components.encodings import NeRFEncoding +from nerfstudio.field_components.field_heads import ( + DensityFieldHead, + FieldHeadNames, + RGBFieldHead, +) +from nerfstudio.field_components.mlp import MLP +from nerfstudio.model_components import renderers +from nerfstudio.model_components.losses import MSELoss +from nerfstudio.model_components.ray_samplers import PDFSampler, Sampler, UniformSampler +from nerfstudio.model_components.renderers import ( + AccumulationRenderer, + DepthRenderer, + RGBRenderer, +) +from nerfstudio.utils import colors +from nerfstudio.models.base_model import Model, ModelConfig +from nerfstudio.utils import colormaps, misc +from rich.console import Console +from skimage.metrics import structural_similarity +from torch import nn +from torch.nn import Parameter +from torchmetrics import PeakSignalNoiseRatio +from torchmetrics.functional import structural_similarity_index_measure +from torchmetrics.image.lpip import LearnedPerceptualImagePatchSimilarity + +from ..utils.extension import TetrahedraTracer, interpolate_values, triangulate + +CONSOLE = Console(width=120) + +try: + os.environ["XLA_PYTHON_CLIENT_PREALLOCATE"] = "false" + os.environ["JAX_PLATFORM_NAME"] = "cpu" + import dm_pix as pix + import jax + + jax_ssim = jax.jit(pix.ssim) + + def mipnerf_ssim(image, rgb): + values = [ + float(jax_ssim(gt, img)) + for gt, img in zip(image.cpu().permute(0, 2, 3, 1).numpy(), rgb.cpu().permute(0, 2, 3, 1).numpy()) + ] + return sum(values) / len(values) + +except ImportError: + CONSOLE.print("[yellow]JAX not installed, skipping Mip-NeRF SSIM[/yellow]") + mipnerf_ssim = None + + +def skimage_ssim(image, rgb): + # Scikit implementation used in PointNeRF + values = [ + structural_similarity(gt, img, win_size=11, multichannel=True, channel_axis=2, data_range=1.0) + for gt, img in zip(image.cpu().permute(0, 2, 3, 1).numpy(), rgb.cpu().permute(0, 2, 3, 1).numpy()) + ] + return sum(values) / len(values) + + +@dataclass +class TetrahedraNerfConfig(ModelConfig): + _target: Any = dataclasses.field(default_factory=lambda: TetrahedraNerf) + tetrahedra_path: Optional[Path] = None + num_tetrahedra_vertices: Optional[int] = None + num_tetrahedra_cells: Optional[int] = None + + max_intersected_triangles: int = 512 + num_samples: int = 256 + num_fine_samples: int = 256 + use_biased_sampler: bool = False + field_dim: int = 64 + + num_color_layers: int = 1 + num_density_layers: int = 3 + hidden_size: int = 128 + + input_fourier_frequencies: int = 0 + + initialize_colors: bool = True + + use_gradient_scaling: bool = False + """Use gradient scaler where the gradients are lower for points closer to the camera.""" + background_color: Literal["random", "last_sample", "black", "white"] = "white" + + appearance_embed_dim: int = 0 + """Embedding dimension for per-image embeddings. Defaults to 0 (no embedding)""" + + use_occupancy_field: bool = False + """Use an occupancy field to determine which tetrahedra are occupied.""" + + def __post_init__(self): + if self.tetrahedra_path is not None and self.num_tetrahedra_vertices is None: + if not self.tetrahedra_path.exists(): + raise RuntimeError(f"Tetrahedra path {self.tetrahedra_path} does not exist") + tetrahedra = torch.load(self.tetrahedra_path) + self.num_tetrahedra_vertices = len(tetrahedra["vertices"]) + self.num_tetrahedra_cells = len(tetrahedra["cells"]) + + +@dataclass +class TetraPointFilterConfig: + enabled: bool = True + + # Conservative defaults first + radial_keep_quantile: float = 0.995 # keep 99.5% + z_keep_min_quantile: float = 0.002 # drop bottom 0.2% + z_keep_max_quantile: float = 1.0 # keep full top side for now + + # Optional light deduplication + voxel_size: Optional[float] = None # e.g. 5e-5 or 1e-4 after transform + max_points: Optional[int] = None # e.g. 120000 if needed later + + verbose: bool = True + + +def _apply_transform_and_scale( + points_xyz: torch.Tensor, + dataparser_transform: torch.Tensor, + dataparser_scale: float, +) -> torch.Tensor: + pts = points_xyz.float() + + tf = dataparser_transform.float() + if tf.shape == (3, 4): + R = tf[:, :3] + t = tf[:, 3] + elif tf.shape == (4, 4): + R = tf[:3, :3] + t = tf[:3, 3] + else: + raise ValueError(f"Unexpected dataparser_transform shape: {tuple(tf.shape)}") + + pts = pts @ R.T + t + pts = pts * float(dataparser_scale) + return pts + + +def _quantile_str(x: torch.Tensor, qs=(0.0, 0.5, 0.95, 0.99, 1.0)) -> str: + vals = torch.quantile(x.float().cpu(), torch.tensor(qs, dtype=torch.float32)) + return ", ".join([f"q{int(q*1000)/10:g}={v.item():.6g}" for q, v in zip(qs, vals)]) + + +def _deduplicate_by_voxel(points: torch.Tensor, voxel_size: float) -> torch.Tensor: + if voxel_size is None or voxel_size <= 0: + return points + + device = points.device + scaled = torch.floor(points / voxel_size).to(torch.int64) + _, unique_idx = torch.unique(scaled, dim=0, return_index=True) + unique_idx = unique_idx.sort().values + return points[unique_idx.to(device)] + +def _filter_points_for_tetra( + points_xyz: torch.Tensor, + dataparser_transform: torch.Tensor, + dataparser_scale: float, + cfg: TetraPointFilterConfig, +) -> Tuple[torch.Tensor, torch.Tensor, dict]: + # IMPORTANT TEST: + # metadata points may already be in dataparser/model space + pts = points_xyz.float() + + stats = { + "num_points_raw": int(pts.shape[0]), + } + + kept_idx = torch.arange(pts.shape[0], dtype=torch.long, device=pts.device) + + if not cfg.enabled: + stats["num_points_final"] = int(pts.shape[0]) + return pts, kept_idx, stats + + keep = torch.ones(pts.shape[0], dtype=torch.bool, device=pts.device) + + # 1) radial tail pruning + center = pts.mean(dim=0, keepdim=True) + radial = torch.linalg.norm(pts - center, dim=-1) + if cfg.radial_keep_quantile < 1.0: + radial_q = torch.quantile(radial, cfg.radial_keep_quantile) + keep &= radial <= radial_q + else: + radial_q = radial.max() + + # 2) asymmetric z-tail pruning + z = pts[:, 2] + z_lo = torch.quantile(z, cfg.z_keep_min_quantile) if cfg.z_keep_min_quantile > 0 else z.min() + z_hi = torch.quantile(z, cfg.z_keep_max_quantile) if cfg.z_keep_max_quantile < 1.0 else z.max() + keep &= (z >= z_lo) & (z <= z_hi) + + pts_filtered = pts[keep] + kept_idx = kept_idx[keep] + + # 3) optional voxel dedup + before_voxel = pts_filtered.shape[0] + if cfg.voxel_size is not None and cfg.voxel_size > 0: + scaled = torch.floor(pts_filtered / cfg.voxel_size).to(torch.int64) + _, unique_idx = torch.unique(scaled, dim=0, return_index=True) + unique_idx = unique_idx.sort().values.to(pts_filtered.device) + pts_filtered = pts_filtered[unique_idx] + kept_idx = kept_idx[unique_idx] + after_voxel = pts_filtered.shape[0] + + # 4) optional hard cap + if cfg.max_points is not None and pts_filtered.shape[0] > cfg.max_points: + idx = torch.randperm(pts_filtered.shape[0], device=pts_filtered.device)[: cfg.max_points] + pts_filtered = pts_filtered[idx] + kept_idx = kept_idx[idx] + + stats.update({ + "num_points_after_mask": int(before_voxel), + "num_points_after_voxel": int(after_voxel), + "num_points_final": int(pts_filtered.shape[0]), + "radial_keep_quantile": float(cfg.radial_keep_quantile), + "z_keep_min_quantile": float(cfg.z_keep_min_quantile), + "z_keep_max_quantile": float(cfg.z_keep_max_quantile), + "z_range_after": ( + float(pts_filtered[:, 2].min().item()), + float(pts_filtered[:, 2].max().item()), + ) if pts_filtered.numel() > 0 else None, + "radial_stats_after": _quantile_str( + torch.linalg.norm(pts_filtered - pts_filtered.mean(dim=0, keepdim=True), dim=-1) + ) if pts_filtered.numel() > 0 else "empty", + }) + + if cfg.verbose: + print("Filtered tetra points:") + for k, v in stats.items(): + print(f" {k}: {v}") + + return pts_filtered, kept_idx, stats + +# Map from uniform space to transformed space +def map_from_real_distances_to_biased_with_bounds(num_bounds, bounds, samples): + lengths = (bounds[..., 1] - bounds[..., 0]).clamp_min_(0) + bounds_start = bounds[..., 0, 0] + bounds_end = torch.gather(bounds[..., 1], 1, (num_bounds[:, None] - 1).clamp_min_(0)).squeeze(-1) + unisamples = (samples - bounds_start[..., None]) / (bounds_end - bounds_start)[..., None] + rest = unisamples.mul_(num_bounds[..., None]) + intervals = rest.floor().clamp_max_(num_bounds[..., None] - 1).clamp_min_(0) + rest = rest - intervals + intervals = intervals.long() + cum_lengths = torch.cumsum(torch.cat((bounds_start[:, None], lengths), 1), 1) + mapped_samples = torch.gather(cum_lengths, 1, intervals) + torch.gather(lengths, 1, intervals) * rest + return mapped_samples + + +class TetrahedraSampler(Sampler): + """Sample points according to a function. + + Args: + num_samples: Number of samples per ray + train_stratified: Use stratified sampling during training. Defaults to True + """ + + def __init__( + self, + num_samples: Optional[int] = None, + train_stratified=True, + ) -> None: + super().__init__(num_samples=num_samples) + self.train_stratified = train_stratified + + def generate_ray_samples( + self, + ray_bundle: Optional[RayBundle] = None, + num_samples: Optional[int] = None, + *, + num_visited_cells, + hit_distances, + ) -> RaySamples: + """Generates position samples according to spacing function. + + Args: + ray_bundle: Rays to generate samples for + num_samples: Number of samples per ray + + Returns: + Positions and deltas for samples along a ray + """ + assert ray_bundle is not None + assert ray_bundle.nears is not None + assert ray_bundle.fars is not None + + num_samples = num_samples or self.num_samples + assert num_samples is not None + num_rays = ray_bundle.origins.shape[0] + + bins = torch.linspace(0.0, 1.0, num_samples + 1).to(ray_bundle.origins.device)[None, ...] # [1, num_samples+1] + + # TODO More complicated than it needs to be. + if self.train_stratified and self.training: + t_rand = torch.rand((num_rays, num_samples + 1), dtype=bins.dtype, device=bins.device) + bin_centers = (bins[..., 1:] + bins[..., :-1]) / 2.0 + bin_upper = torch.cat([bin_centers, bins[..., -1:]], -1) + bin_lower = torch.cat([bins[..., :1], bin_centers], -1) + bins = bin_lower + (bin_upper - bin_lower) * t_rand + + s_near, s_far = ray_bundle.nears, ray_bundle.fars + spacing_to_euclidean_fn = lambda x: x * s_far + (1 - x) * s_near + euclidean_bins = spacing_to_euclidean_fn(bins) + euclidean_bins = map_from_real_distances_to_biased_with_bounds( + num_visited_cells.long(), hit_distances, euclidean_bins + ) + bins = (euclidean_bins - s_near) / (s_far - s_near) + + ray_samples = ray_bundle.get_ray_samples( + bin_starts=euclidean_bins[..., :-1, None], + bin_ends=euclidean_bins[..., 1:, None], + spacing_starts=bins[..., :-1, None], + spacing_ends=bins[..., 1:, None], + spacing_to_euclidean_fn=spacing_to_euclidean_fn, + ) + + return ray_samples + + +class GradientScaler(torch.autograd.Function): + @staticmethod + def forward(ctx, colors, sigmas, ray_dist): + ctx.save_for_backward(ray_dist) + return colors, sigmas, ray_dist + + @staticmethod + def backward(ctx, grad_output_colors, grad_output_sigmas, grad_output_ray_dist): + (ray_dist,) = ctx.saved_tensors + scaling = torch.square(ray_dist).clamp(0, 1) + return grad_output_colors * scaling, grad_output_sigmas * scaling, grad_output_ray_dist + + +# pylint: disable=attribute-defined-outside-init +class TetrahedraNerf(Model): + """Tetrahedra NeRF model + + Args: + config: Basic NeRF configuration to instantiate model + """ + + config: TetrahedraNerfConfig + + def __init__( + self, + config: TetrahedraNerfConfig, + dataparser_transform=None, + dataparser_scale=None, + metadata=None, + **kwargs, + ) -> None: + super().__init__( + config=config, + **kwargs, + ) + self.dataparser_transform = dataparser_transform + self.dataparser_scale = dataparser_scale + self._tetrahedra_tracer = None + self._step = 0 + if self.config.tetrahedra_path is None and metadata is not None and "points3D_xyz" in metadata: + self._load_points_from_metadata(**metadata) + else: + if self.config.num_tetrahedra_vertices is None or self.config.num_tetrahedra_cells is None: + raise RuntimeError("The tetrahedra_path must be specified.") + self.register_buffer( + "tetrahedra_vertices", + torch.empty((self.config.num_tetrahedra_vertices, 3), dtype=torch.float32), + ) + self.register_buffer( + "tetrahedra_cells", + torch.empty((self.config.num_tetrahedra_cells, 4), dtype=torch.int32), + ) + self.register_parameter( + "tetrahedra_field", + nn.Parameter( + torch.empty( + (self.config.field_dim, self.config.num_tetrahedra_vertices), + dtype=torch.float32, + ) + ), + ) + if self.config.use_occupancy_field: + self.register_buffer( + "tetrahedra_occupancy", + nn.Parameter( + torch.zeros( + (self.config.num_tetrahedra_cells,), + dtype=torch.float32, + ) + ), + ) + self._tetrahedra_initialized = False + + @staticmethod + def _init_tetrahedra_field(tetrahedra_field): + scale = 1e-4 + tetrahedra_field.uniform_(-scale, scale) + + def _load_from_state_dict( + self, + state_dict, + prefix, + local_metadata, + strict, + missing_keys, + unexpected_keys, + error_msgs, + ): + will_initialize = False + if ( + f"{prefix}tetrahedra_vertices" in state_dict + and f"{prefix}tetrahedra_cells" in state_dict + and f"{prefix}tetrahedra_field" in state_dict + ): + will_initialize = True + super()._load_from_state_dict( + state_dict, + prefix, + local_metadata, + strict, + missing_keys, + unexpected_keys, + error_msgs, + ) + if will_initialize: + self._tetrahedra_initialized = True + + def _load_points_from_metadata(self, points3D_xyz, points3D_rgb=None, **kwargs): + CONSOLE.print("Loading points from data parser") + + # Safety + if self.dataparser_transform is None or self.dataparser_scale is None: + raise RuntimeError( + "Missing dataparser transform/scale. Use TetrahedraNerfPipeline." + ) + + if not isinstance(points3D_xyz, torch.Tensor): + points3D_xyz = torch.tensor(points3D_xyz, dtype=torch.float32) + points3D_xyz = points3D_xyz.float().cpu() + + # ============================== + # 🔥 PRESET SWITCH (manual) + # ============================== + PRESET = os.environ.get("TETRA_FILTER_PRESET", "A").upper() # change: "OFF", "A", "B", "C" + + if PRESET == "OFF": + tetra_filter_cfg = TetraPointFilterConfig(enabled=False) + + elif PRESET == "A": + tetra_filter_cfg = TetraPointFilterConfig( + enabled=True, + radial_keep_quantile=1.0, + z_keep_min_quantile=0.0001, + z_keep_max_quantile=1.0, + voxel_size=None, + verbose=True, + ) + + elif PRESET == "B": + tetra_filter_cfg = TetraPointFilterConfig( + enabled=True, + radial_keep_quantile=1.0, + z_keep_min_quantile=0.0002, + z_keep_max_quantile=1.0, + voxel_size=None, + verbose=True, + ) + + elif PRESET == "C": + tetra_filter_cfg = TetraPointFilterConfig( + enabled=True, + radial_keep_quantile=1.0, + z_keep_min_quantile=0.0005, + z_keep_max_quantile=1.0, + voxel_size=None, + verbose=True, + ) + + elif PRESET == "D": + tetra_filter_cfg = TetraPointFilterConfig( + enabled=True, + radial_keep_quantile=0.999, + z_keep_min_quantile=0.0001, + z_keep_max_quantile=1.0, + voxel_size=None, + verbose=True, + ) + + elif PRESET == "E": + tetra_filter_cfg = TetraPointFilterConfig( + enabled=True, + radial_keep_quantile=0.995, + z_keep_min_quantile=0.0001, + z_keep_max_quantile=1.0, + voxel_size=None, + verbose=True, + ) + + else: + raise ValueError(f"Unknown PRESET: {PRESET}") + + # ============================== + # 🔥 FILTER (IMPORTANT) + # ============================== + tetrahedra_vertices, kept_idx, stats = _filter_points_for_tetra( + points_xyz=points3D_xyz, + dataparser_transform=self.dataparser_transform.cpu(), + dataparser_scale=float(self.dataparser_scale), + cfg=tetra_filter_cfg, + ) + + # ============================== + # 🔥 TRIANGULATE FILTERED + # ============================== + tetrahedra_cells = triangulate(tetrahedra_vertices.contiguous()).int() + + # ============================== + # REGISTER + # ============================== + num_vertices = len(tetrahedra_vertices) + + self.config.num_tetrahedra_vertices = num_vertices + self.config.num_tetrahedra_cells = len(tetrahedra_cells) + + self.register_buffer("tetrahedra_vertices", tetrahedra_vertices) + self.register_buffer("tetrahedra_cells", tetrahedra_cells.to(torch.int32)) + + self.register_parameter( + "tetrahedra_field", + nn.Parameter( + torch.empty( + (self.config.field_dim, num_vertices), + dtype=torch.float32, + ) + ), + ) + + if self.config.use_occupancy_field: + self.register_buffer( + "tetrahedra_occupancy", + nn.Parameter( + torch.zeros( + (self.config.num_tetrahedra_cells,), + dtype=torch.float32, + ) + ), + ) + + self._init_tetrahedra_field(self.tetrahedra_field.data) + + # ============================== + # COLOR INIT (FIXED) + # ============================== + if self.config.initialize_colors and points3D_rgb is not None: + assert points3D_rgb.dtype == torch.uint8 + assert points3D_rgb.shape[0] == points3D_xyz.shape[0] + + filtered_rgb = points3D_rgb[kept_idx.cpu()] + colors = filtered_rgb.float().to(self.tetrahedra_field.device) * 2.0 / 255.0 - 1.0 + self.tetrahedra_field.data[1:4, :] = colors[:, :3].T + self.tetrahedra_field.data[0, :] = 1.0 + else: + # still keep the density-compatible init + self.tetrahedra_field.data[0, :] = 1.0 + + # ============================== + # DEBUG PRINTS (CRITICAL) + # ============================== + CONSOLE.print("\nFiltered tetra stats:") + for k, v in stats.items(): + CONSOLE.print(f" {k}: {v}") + + CONSOLE.print("\nTetrahedra initialized from dataparser:") + CONSOLE.print(f" Num points (raw): {len(points3D_xyz)}") + CONSOLE.print(f" Num points (filtered): {len(self.tetrahedra_vertices)}") + CONSOLE.print(f" Num tetrahedra: {len(self.tetrahedra_cells)}") + + self._tetrahedra_initialized = True + def _init_tetrahedra(self): + if self.config.tetrahedra_path is not None: + if not self.config.tetrahedra_path.exists(): + raise RuntimeError(f"Specified tetrahedra path {self.config.tetrahedra_path} does not exist") + tetrahedra = torch.load(str(self.config.tetrahedra_path), map_location=torch.device("cpu")) + tetrahedra_vertices = tetrahedra["vertices"].float() + + # Transform vertices using the dataparser transforms + if self.dataparser_scale is None: + raise RuntimeError( + "Could not read the dataparser_scale and dataparser_transform parameters." + "Make sure you are using the TetrahedraNerfPipeline with the model." + ) + + tetrahedra_vertices = ( + torch.cat( + ( + tetrahedra_vertices, + torch.ones_like(tetrahedra_vertices[..., :1]), + ), + -1, + ) + @ self.dataparser_transform.T + ) + tetrahedra_vertices *= self.dataparser_scale + + tetrahedra_cells = tetrahedra["cells"].int() + num_tetrahedra_vertices = len(tetrahedra_vertices) + self.tetrahedra_vertices.copy_(tetrahedra_vertices.to(device=self.tetrahedra_vertices.device)) + self.tetrahedra_cells.copy_(tetrahedra_cells.to(device=self.tetrahedra_cells.device)) + self._init_tetrahedra_field(self.tetrahedra_field.data) + if self.config.initialize_colors: + assert "colors" in tetrahedra + assert tetrahedra["colors"].dtype == torch.uint8 + assert tetrahedra["colors"].shape == (num_tetrahedra_vertices, 4) + colors = tetrahedra["colors"].float().to(self.tetrahedra_field.device) * 2.0 / 255.0 - 1.0 + self.tetrahedra_field.data[1:4, :] = colors[:, :3].T + self.tetrahedra_field.data[0, :] = colors[:, 3] + CONSOLE.print(f"Tetrahedra initialized from file {self.config.tetrahedra_path}:") + CONSOLE.print(f" Num points: {len(self.tetrahedra_vertices)}") + CONSOLE.print(f" Num tetrahedra: {len(self.tetrahedra_cells)}") + self._tetrahedra_initialized = True + else: + raise RuntimeError("The tetrahedra_path must be specified.") + + def get_tetrahedra_tracer(self): + device = self.tetrahedra_field.device + if device.type != "cuda": + raise RuntimeError("Tetrahedra tracer is only supported on a CUDA device") + if self._tetrahedra_tracer is not None: + if self._tetrahedra_tracer.device == device: + return self._tetrahedra_tracer + del self._tetrahedra_tracer + self._tetrahedra_tracer = None + if not self._tetrahedra_initialized: + self._init_tetrahedra() + self._tetrahedra_tracer = TetrahedraTracer(device) + self._tetrahedra_tracer.load_tetrahedra(self.tetrahedra_vertices, self.tetrahedra_cells) + return self._tetrahedra_tracer + + def populate_modules(self): + """Set the fields and modules""" + super().populate_modules() + + # fields + mlp_in_dim = self.config.field_dim + if self.config.input_fourier_frequencies > 0: + self.position_encoding = NeRFEncoding( + in_dim=self.config.field_dim, + num_frequencies=self.config.input_fourier_frequencies, + min_freq_exp=0.0, + max_freq_exp=float(self.config.input_fourier_frequencies), + include_input=True, + ) + mlp_in_dim += self.position_encoding.get_out_dim() + else: + self.position_encoding = lambda x: x + self.direction_encoding = NeRFEncoding( + in_dim=3, + num_frequencies=4, + min_freq_exp=0.0, + max_freq_exp=4.0, + include_input=True, + ) + self.mlp_base = MLP( + in_dim=mlp_in_dim, + num_layers=self.config.num_density_layers, + layer_width=self.config.hidden_size, + out_activation=nn.ReLU(), + ) + head_input_dim = self.mlp_base.get_out_dim() + self.direction_encoding.get_out_dim() + if self.config.appearance_embed_dim > 0: + self.appearance_embedding = nn.Embedding( + self.num_train_data, + self.config.appearance_embed_dim, + ) + head_input_dim += self.config.appearance_embed_dim + + self.mlp_head = MLP( + in_dim=head_input_dim, + num_layers=self.config.num_color_layers, + layer_width=self.config.hidden_size, + out_activation=nn.ReLU(), + ) + + self.field_output_color = RGBFieldHead(in_dim=self.mlp_head.get_out_dim()) + self.field_output_density = DensityFieldHead(in_dim=self.mlp_base.get_out_dim()) + + # samplers + if self.config.use_biased_sampler: + self.sampler_uniform = TetrahedraSampler(num_samples=self.config.num_samples) + else: + self.sampler_uniform = UniformSampler(num_samples=self.config.num_samples) + if self.config.num_fine_samples > 0: + self.sampler_pdf = PDFSampler(num_samples=self.config.num_fine_samples) + + # renderers + self.renderer_rgb = RGBRenderer(background_color=self.config.background_color) + self.renderer_accumulation = AccumulationRenderer() + self.renderer_depth = DepthRenderer() + + # losses + self.rgb_loss = MSELoss() + + # metrics + self.psnr = PeakSignalNoiseRatio(data_range=1.0) + self.skimage_ssim = skimage_ssim + self.nerfstudio_ssim = structural_similarity_index_measure + self.lpips = LearnedPerceptualImagePatchSimilarity() + # self.lpips_vgg = LearnedPerceptualImagePatchSimilarity(net_type="vgg") + + # Just to allow for size reduction of the checkpoint + def load_state_dict(self, state_dict, *args, **kwargs): + for k, v in self.lpips.state_dict().items(): + state_dict[f"lpips.{k}"] = v + if hasattr(self, "lpips_vgg"): + for k, v in self.lpips_vgg.state_dict().items(): + state_dict[f"lpips_vgg.{k}"] = v + return super().load_state_dict(state_dict, *args, **kwargs) + + # Just to allow for size reduction of the checkpoint + def state_dict(self, *args, prefix="", **kwargs): + state_dict = super().state_dict(*args, prefix=prefix, **kwargs) + for k in list(state_dict.keys()): + if k.startswith(f"{prefix}lpips.") or k.startswith(f"{prefix}lpips_vgg."): + state_dict.pop(k) + return state_dict + + def get_param_groups(self) -> Dict[str, List[Parameter]]: + param_groups = {} + if self.mlp_base is None: + raise ValueError("populate_fields() must be called before get_param_groups") + param_groups["fields"] = list(self.parameters()) + return param_groups + + def get_background_color(self, shape, device): + if hasattr(self.renderer_rgb, "get_background_color"): + return self.renderer_rgb.get_background_color(self.renderer_rgb.background_color, shape, device) + # NOTE: this is here for older NS versions + background_color = self.config.background_color + if renderers.BACKGROUND_COLOR_OVERRIDE is not None: + background_color = renderers.BACKGROUND_COLOR_OVERRIDE + if background_color == "random": + return torch.rand(shape, dtype=torch.float32, device=device) + if isinstance(background_color, str) and background_color in colors.COLORS_DICT: + background_color = colors.COLORS_DICT[background_color] + assert isinstance(background_color, torch.Tensor) + + # Ensure correct shape + return background_color.expand(shape).to(device).contiguous() + + def get_outputs(self, ray_bundle: RayBundle): + assert self.collider is not None + if self.mlp_base is None: + raise ValueError("populate_fields() must be called before get_outputs") + + tracer = self.get_tetrahedra_tracer() + tracer_output = tracer.trace_rays( + ray_bundle.origins.contiguous(), + ray_bundle.directions.contiguous(), + self.config.max_intersected_triangles, + ) + num_visited_cells = tracer_output["num_visited_cells"] + nears = tracer_output["hit_distances"][:, 0, 0][:, None] + fars = torch.gather( + tracer_output["hit_distances"][:, :, 1], + 1, + (num_visited_cells[:, None].long() - 1).clamp_min_(0), + ) + + # Reduce everything to nonempty rays + ray_mask = tracer_output["num_visited_cells"] > 0 + nears_r = nears[ray_mask] + fars_r = fars[ray_mask] + if nears_r.shape[0] > 0: + ray_bundle_modified_r = dataclasses.replace(ray_bundle[ray_mask], nears=nears_r, fars=fars_r) + + # Apply biased sampling + visited_tetrahedra = tracer_output["visited_cells"][ray_mask] + ray_samples_r: RaySamples + if isinstance(self.sampler_uniform, TetrahedraSampler): + ray_samples_r = self.sampler_uniform( + ray_bundle_modified_r, + num_visited_cells=tracer_output["num_visited_cells"][ray_mask], + hit_distances=tracer_output["hit_distances"][ray_mask], + ) + else: + ray_samples_r = self.sampler_uniform(ray_bundle_modified_r) + distances_r = (ray_samples_r.frustums.ends + ray_samples_r.frustums.starts) / 2 + + # Trace matched cells and interpolate field + traced_cells = tracer.find_visited_cells( + tracer_output["num_visited_cells"][ray_mask], + visited_tetrahedra, + tracer_output["barycentric_coordinates"][ray_mask], + tracer_output["hit_distances"][ray_mask], + tracer_output["vertex_indices"][ray_mask], + distances_r.squeeze(-1), + ) + barycentric_coords = traced_cells["barycentric_coordinates"] + field_values = interpolate_values( + traced_cells["vertex_indices"], + barycentric_coords, + self.tetrahedra_field, + ) + + if self.config.num_fine_samples > 0: + # apply MLP on top + encoded_abc = self.position_encoding(field_values) + base_mlp_out = self.mlp_base(encoded_abc) + + # Apply dense, fine sampling + density_coarse = self.field_output_density(base_mlp_out) + weights = ray_samples_r.get_weights(density_coarse) + # pdf sampling + ray_samples_r = self.sampler_pdf(ray_bundle_modified_r, ray_samples_r, weights) + distances_r = (ray_samples_r.frustums.ends + ray_samples_r.frustums.starts) / 2 + + traced_cells = tracer.find_visited_cells( + tracer_output["num_visited_cells"][ray_mask], + tracer_output["visited_cells"][ray_mask], + tracer_output["barycentric_coordinates"][ray_mask], + tracer_output["hit_distances"][ray_mask], + tracer_output["vertex_indices"][ray_mask], + distances_r.squeeze(-1), + ) + barycentric_coords = traced_cells["barycentric_coordinates"] + field_values = interpolate_values( + traced_cells["vertex_indices"], + barycentric_coords, + self.tetrahedra_field, + ) + + encoded_abc = self.position_encoding(field_values) + base_mlp_out = self.mlp_base(encoded_abc) + + field_outputs = {} + field_outputs[self.field_output_density.field_head_name] = self.field_output_density(base_mlp_out) + encoded_dir = self.direction_encoding(ray_samples_r.frustums.directions) + mlp_out = [encoded_dir, base_mlp_out] + if self.config.appearance_embed_dim > 0: + # appearance + if self.training: + assert ray_samples_r.camera_indices is not None + camera_indices = ray_samples_r.camera_indices.squeeze() + embedded_appearance = self.appearance_embedding(camera_indices) + else: + embedded_appearance = torch.ones( + (*encoded_dir.shape[:-1], self.config.appearance_embed_dim), device=encoded_dir.device + ) * self.appearance_embedding.weight.mean(dim=0) + mlp_out.append(embedded_appearance) + mlp_out = self.mlp_head(torch.cat(mlp_out, dim=-1)) # type: ignore + field_outputs[self.field_output_color.field_head_name] = self.field_output_color(mlp_out) + + colors = field_outputs[FieldHeadNames.RGB] + sigmas = field_outputs[FieldHeadNames.DENSITY] + if self.config.use_gradient_scaling: + # NOTE: we multiply the ray distance by 2 because according to the + # Radiance Field Gradient Scaling for Unbiased Near-Camera Training + # paper, it is the distance to the object center + ray_dist = ray_samples_r.spacing_ends + ray_samples_r.spacing_starts + colors, sigmas, ray_dist = GradientScaler.apply(colors, sigmas, ray_dist) + + weights = ray_samples_r.get_weights(sigmas) + rgb_r = self.renderer_rgb( + rgb=colors, + weights=weights, + ) + accumulation_r = self.renderer_accumulation(weights) + depth_r = self.renderer_depth(weights, ray_samples_r) + + # Expand rendered values back to the original shape + device = ray_mask.device + rgb = self.get_background_color((ray_mask.shape[0], 3), device=device) + # rgb = torch.zeros((ray_mask.shape[0], 3), dtype=torch.float32, device=device) + accumulation = torch.zeros((ray_mask.shape[0], 1), dtype=torch.float32, device=device) + depth = torch.full( + (ray_mask.shape[0], 1), + self.collider.far_plane, + dtype=torch.float32, + device=device, + ) + if nears_r.shape[0] > 0: + rgb[ray_mask] = rgb_r + accumulation[ray_mask] = accumulation_r + depth[ray_mask] = depth_r + + outputs = { + "rgb": rgb, + "accumulation": accumulation, + "depth": depth, + "ray_mask": ray_mask, + } + return outputs + + # pylint: disable=unused-argument + def get_loss_dict(self, outputs, batch, metrics_dict=None) -> Dict[str, torch.Tensor]: + # Scaling metrics by coefficients to create the losses. + device = outputs["rgb"].device + image = batch["image"].to(device) + + rgb_loss = self.rgb_loss(image, outputs["rgb"]) + + loss_dict = {"rgb_loss": rgb_loss} + loss_dict = misc.scale_dict(loss_dict, self.config.loss_coefficients) + return loss_dict + + def get_image_metrics_and_images( + self, outputs: Dict[str, torch.Tensor], batch: Dict[str, torch.Tensor] + ) -> Tuple[Dict[str, float], Dict[str, torch.Tensor]]: + image = batch["image"].to(outputs["rgb"].device) + rgb = outputs["rgb"] + acc = colormaps.apply_colormap(outputs["accumulation"]) + depth = colormaps.apply_depth_colormap( + outputs["depth"], + accumulation=outputs["accumulation"], + ) + + combined_rgb = torch.cat([image, rgb], dim=1) + combined_acc = torch.cat([acc], dim=1) + combined_depth = torch.cat([depth], dim=1) + + # Switch images from [H, W, C] to [1, C, H, W] for metrics computations + image = torch.moveaxis(image, -1, 0)[None, ...] + rgb = torch.moveaxis(rgb, -1, 0)[None, ...] + + psnr = self.psnr(image, rgb) + lpips = self.lpips(image, rgb) + + # "lpips_vgg": float(self.lpips_vgg(image, rgb)), + metrics_dict = { + "psnr": float(psnr.item()), + "nerfstudio_ssim": float(self.nerfstudio_ssim(image, rgb)), + "skimage_ssim": float(self.skimage_ssim(image, rgb)), + "lpips": float(lpips), + } + if mipnerf_ssim is not None: + metrics_dict["mipnerf_ssim"] = float(mipnerf_ssim(image, rgb)) + + images_dict = { + "img": combined_rgb, + "accumulation": combined_acc, + "depth": combined_depth, + } + return metrics_dict, images_dict diff --git a/Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/pipeline.py b/Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/pipeline.py new file mode 100644 index 0000000000..026af04c3b --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/pipeline.py @@ -0,0 +1,59 @@ +import typing +from torch.cuda.amp.grad_scaler import GradScaler + +from nerfstudio.data.datamanagers.base_datamanager import VanillaDataManager +from nerfstudio.pipelines.base_pipeline import ( + DDP, + Model, + Pipeline, + VanillaPipeline, + VanillaPipelineConfig, + dist, +) +from typing_extensions import Literal + + +class TetrahedraNerfPipeline(VanillaPipeline): + def __init__( + self, + config: VanillaPipelineConfig, + device: str, + test_mode: Literal["test", "val", "inference"] = "val", + world_size: int = 1, + local_rank: int = 0, + grad_scaler: typing.Optional[GradScaler] = None, + ): + Pipeline.__init__(self) + self.config = config + self.test_mode = test_mode + self.datamanager: VanillaDataManager = config.datamanager.setup( + device=device, + test_mode=test_mode, + world_size=world_size, + local_rank=local_rank, + ) + if hasattr(self.datamanager, "to"): + self.datamanager.to(device) + assert self.datamanager.train_dataset is not None, "Missing input dataset" + + # Loaded pointcloud must be transformed using the transform from the Dataparser + kwargs = {} # Compatible with NerfStudio<0.3.0, where the parameter did not exist + if grad_scaler is not None: + kwargs["grad_scaler"] = grad_scaler + self._model = config.model.setup( + scene_box=self.datamanager.train_dataset.scene_box, + dataparser_transform=self.datamanager.train_dataparser_outputs.dataparser_transform, + dataparser_scale=self.datamanager.train_dataparser_outputs.dataparser_scale, + num_train_data=len(self.datamanager.train_dataset), + metadata=self.datamanager.train_dataset.metadata, + **kwargs, + ) + self.model.to(device) + + self.world_size = world_size + if world_size > 1: + self._model = typing.cast( + Model, + DDP(self._model, device_ids=[local_rank], find_unused_parameters=True), + ) + dist.barrier(device_ids=[local_rank]) \ No newline at end of file diff --git a/Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/registration.py b/Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/registration.py new file mode 100644 index 0000000000..e7d2279589 --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/tetranerf/nerfstudio/registration.py @@ -0,0 +1,69 @@ +import typing +from functools import partial +import dataclasses +from nerfstudio.data.datamanagers.base_datamanager import VanillaDataManagerConfig +from nerfstudio.engine.optimizers import RAdamOptimizerConfig +from nerfstudio.engine.schedulers import ExponentialDecaySchedulerConfig +from nerfstudio.engine.trainer import TrainerConfig +from nerfstudio.pipelines.base_pipeline import VanillaPipelineConfig +from nerfstudio.plugins.types import MethodSpecification +try: + from nerfstudio.data.dataparsers.colmap_dataparser import ColmapDataParserConfig + DPConfig = partial(ColmapDataParserConfig, load_3D_points=True) +except ImportError: + # Older NerfStudio versions + from nerfstudio.data.dataparsers.minimal_dataparser import MinimalDataParserConfig as DPConfig # type: ignore +from .model import TetrahedraNerf, TetrahedraNerfConfig +from .pipeline import TetrahedraNerfPipeline + +#Cli Integration +import tetranerf.nerfstudio.registration + +tetranerf_original_config = TrainerConfig( + method_name="tetra-nerf-original", + pipeline=VanillaPipelineConfig( + _target=TetrahedraNerfPipeline, + datamanager=VanillaDataManagerConfig( + # _target=RayPruningDataManager, + dataparser=DPConfig(), + eval_num_rays_per_batch=4096, + train_num_rays_per_batch=4096, + ), + model=TetrahedraNerfConfig(_target=TetrahedraNerf), + ), + max_num_iterations=300000, + steps_per_save=25000, + steps_per_eval_batch=1000, + steps_per_eval_image=2000, + steps_per_eval_all_images=50000, + optimizers={ + "fields": { + "optimizer": RAdamOptimizerConfig(lr=0.001), + "scheduler": ExponentialDecaySchedulerConfig( + lr_final=0.0001, + max_steps=300_000, + ), + }, + }, +) + +tetranerf_config = dataclasses.replace( + tetranerf_original_config, + method_name="tetra-nerf", + pipeline=dataclasses.replace( + tetranerf_original_config.pipeline, + model=dataclasses.replace( + typing.cast(TetrahedraNerfConfig, tetranerf_original_config.pipeline.model), + num_samples=128, + num_fine_samples=128, + use_biased_sampler=True, + use_gradient_scaling=True, + ), + ), +) +tetranerf_original = MethodSpecification( + config=tetranerf_original_config, description="Official implementation of Tetra-NeRF paper" +) +tetranerf = MethodSpecification( + config=tetranerf_config, description="Newer version of Tetra-NeRF with better performance" +) diff --git a/Extra-Methods-Patches/tetra-nerf/tetranerf/utils/extension/__init__.py b/Extra-Methods-Patches/tetra-nerf/tetranerf/utils/extension/__init__.py new file mode 100644 index 0000000000..c41d10a68a --- /dev/null +++ b/Extra-Methods-Patches/tetra-nerf/tetranerf/utils/extension/__init__.py @@ -0,0 +1,181 @@ +import os +from pathlib import Path + +_THIS_DIR = Path(__file__).resolve().parent + + +def _existing_dir(*candidates): + for c in candidates: + if not c: + continue + p = Path(str(c)) + if p.exists() and p.is_dir(): + return p + return None + + +def _add_dll_dir(path): + if not path: + return + try: + os.add_dll_directory(str(path)) + except Exception: + pass + + +def _prepend_path(path): + if not path: + return + p = str(path) + old = os.environ.get("PATH", "") + parts = old.split(os.pathsep) if old else [] + norm_p = os.path.normcase(os.path.normpath(p)) + normalized = [os.path.normcase(os.path.normpath(x)) for x in parts if x] + if norm_p not in normalized: + os.environ["PATH"] = p + (os.pathsep + old if old else "") + + +def _register_runtime_dir(path): + if not path: + return + _add_dll_dir(path) + _prepend_path(path) + + +def _candidate_vcpkg_bins(): + candidates = [] + + vcpkg_root = os.environ.get("VCPKG_ROOT") + if vcpkg_root: + candidates.append(Path(vcpkg_root) / "installed" / "x64-windows" / "bin") + candidates.append(Path(vcpkg_root) / "installed" / "x64-windows" / "debug" / "bin") + + candidates.append(Path("C:/vcpkg/installed/x64-windows/bin")) + candidates.append(Path("C:/vcpkg/installed/x64-windows/debug/bin")) + + return candidates + + +def _setup_windows_runtime(): + if os.name != "nt": + return + + conda_prefix = os.environ.get("CONDA_PREFIX") + if conda_prefix: + _register_runtime_dir(Path(conda_prefix) / "Library" / "bin") + _register_runtime_dir(Path(conda_prefix) / "DLLs") + _register_runtime_dir(Path(conda_prefix) / "Lib" / "site-packages" / "torch" / "lib") + + try: + import torch + torch_dir = Path(torch.__file__).resolve().parent + _register_runtime_dir(torch_dir / "lib") + except Exception: + pass + + cuda_root = _existing_dir( + os.environ.get("CUDAToolkit_ROOT"), + os.environ.get("CUDA_HOME"), + os.environ.get("CUDA_PATH"), + r"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8", + ) + if cuda_root: + _register_runtime_dir(cuda_root / "bin") + _register_runtime_dir(cuda_root / "libnvvp") + + optix_root = _existing_dir( + os.environ.get("OPTIX_ROOT_DIR"), + os.environ.get("OPTIX_INSTALL_DIR"), + os.environ.get("OptiX_ROOT_DIR"), + os.environ.get("OptiX_INSTALL_DIR"), + r"C:\Program Files\NVIDIA Corporation\OptiX SDK 9.1.0", + ) + if optix_root: + _register_runtime_dir(optix_root / "bin") + + for p in _candidate_vcpkg_bins(): + if p.exists(): + _register_runtime_dir(p) + + _register_runtime_dir(_THIS_DIR) + + +_setup_windows_runtime() + +import torch + +try: + from . import tetranerf_cpp_extension as cpp +except Exception as err: + print("\033[91;1mERROR: Tetra-NeRF could not load the cpp extension.\033[0m") + print(f"REAL ERROR: {err}") + + class LazyError: + class LazyErrorObj: + def __call__(self, *args, **kwargs): + raise RuntimeError( + "ERROR: Tetra-NeRF could not load cpp extension. Please build the project first." + ) from err + + def __getattribute__(self, name: str): + raise RuntimeError( + "ERROR: Tetra-NeRF could not load cpp extension. Please build the project first." + ) from err + + def __getattribute__(self, name: str): + return LazyError.LazyErrorObj() + + cpp = LazyError() + +TetrahedraTracer = cpp.TetrahedraTracer +triangulate = cpp.triangulate +gather_uint32 = cpp.gather_uint32 +scatter_ema_uint32_ = cpp.scatter_ema_uint32 + + +class _InterpolateValuesFunction(torch.autograd.Function): + @staticmethod + def forward(ctx, vertex_indices, barycentric_coordinates, field): + output = cpp.interpolate_values(vertex_indices, barycentric_coordinates, field) + ctx.save_for_backward(vertex_indices, barycentric_coordinates, field) + return output + + @staticmethod + def backward(ctx, grad_out): + vertex_indices, barycentric_coordinates, field = ctx.saved_tensors + grad_field = cpp.interpolate_values_backward( + vertex_indices, barycentric_coordinates, field, grad_out.contiguous() + ) + return None, None, grad_field + + +class _BarycentricsGradFunction(torch.autograd.Function): + @staticmethod + def forward(ctx, barycentrics, vertices, points): + ctx.save_for_backward(barycentrics, vertices) + return barycentrics + + @staticmethod + def backward(ctx, grad_barycentrics): + barycentrics, vertices = ctx.saved_tensors + grad_vertices = None + grad_points = None + if ctx.needs_input_grad[1] or ctx.needs_input_grad[2]: + t_mat = (vertices[..., 1:, :] - vertices[..., :1, :]) + m_vec = torch.linalg.solve(t_mat, grad_barycentrics) + full_barycentrics = torch.cat( + [1.0 - barycentrics.sum(-1, keepdim=True), barycentrics], -1 + ) + if ctx.needs_input_grad[1]: + grad_vertices = (full_barycentrics.unsqueeze(-1) * m_vec.unsqueeze(-2)).mul_(-1.0) + if ctx.needs_input_grad[2]: + grad_points = m_vec + return grad_barycentrics, grad_vertices, grad_points + + +def add_barycentrics_grad(barycentrics, vertices, points): + return _BarycentricsGradFunction.apply(barycentrics, vertices, points) + + +def interpolate_values(vertex_indices, barycentric_coordinates, field): + return _InterpolateValuesFunction.apply(vertex_indices, barycentric_coordinates, field) \ No newline at end of file diff --git a/Extra-Methods-Patches/zipnerf-pytorch/extensions/cuda/setup.py b/Extra-Methods-Patches/zipnerf-pytorch/extensions/cuda/setup.py new file mode 100644 index 0000000000..75f78f3ad4 --- /dev/null +++ b/Extra-Methods-Patches/zipnerf-pytorch/extensions/cuda/setup.py @@ -0,0 +1,64 @@ +import os +from setuptools import setup +from torch.utils.cpp_extension import BuildExtension, CUDAExtension + +_src_path = os.path.dirname(os.path.abspath(__file__)) + +if os.name == "nt": + nvcc_flags = [ + "-O3", + "-std=c++17", + "-U__CUDA_NO_HALF_OPERATORS__", + "-U__CUDA_NO_HALF_CONVERSIONS__", + "-U__CUDA_NO_HALF2_OPERATORS__", + ] + c_flags = ["/O2", "/std:c++17"] + + def find_cl_path(): + import glob + + for edition in ["Enterprise", "Professional", "BuildTools", "Community"]: + paths = sorted( + glob.glob( + rf"C:\Program Files (x86)\Microsoft Visual Studio\*\{edition}\VC\Tools\MSVC\*\bin\Hostx64\x64" + ), + reverse=True, + ) + if paths: + return paths[0] + return None + + if os.system("where cl.exe >nul 2>nul") != 0: + cl_path = find_cl_path() + if cl_path is None: + raise RuntimeError("Could not locate a supported Microsoft Visual C++ installation") + os.environ["PATH"] += ";" + cl_path + +else: + nvcc_flags = [ + "-O3", + "-std=c++14", + "-U__CUDA_NO_HALF_OPERATORS__", + "-U__CUDA_NO_HALF_CONVERSIONS__", + "-U__CUDA_NO_HALF2_OPERATORS__", + ] + c_flags = ["-O3", "-std=c++14"] + +setup( + name="cuda_backend", + ext_modules=[ + CUDAExtension( + name="_cuda_backend", + sources=[ + os.path.join(_src_path, "src", "gridencoder.cu"), + os.path.join(_src_path, "src", "pdf.cu"), + os.path.join(_src_path, "src", "bindings.cpp"), + ], + extra_compile_args={ + "cxx": c_flags, + "nvcc": nvcc_flags, + }, + ), + ], + cmdclass={"build_ext": BuildExtension}, +) \ No newline at end of file diff --git a/Extra-Methods-Patches/zipnerf-pytorch/extensions/cuda/setup.py.patch b/Extra-Methods-Patches/zipnerf-pytorch/extensions/cuda/setup.py.patch new file mode 100644 index 0000000000..5f76cfbcf1 --- /dev/null +++ b/Extra-Methods-Patches/zipnerf-pytorch/extensions/cuda/setup.py.patch @@ -0,0 +1,12 @@ +diff --git "a/C:\\Users\\crist\\Documents\\nerfstudio_custom\\zipnerf-pytorch\\extensions\\cuda\\setup.py" "b/C:\\Users\\crist\\Documents\\nerfstudio_custom\\Extra-Methods-Patches\\zipnerf-pytorch\\extensions\\cuda\\setup.py" +index a1c7b38c..75f78f3a 100644 +--- "a/C:\\Users\\crist\\Documents\\nerfstudio_custom\\zipnerf-pytorch\\extensions\\cuda\\setup.py" ++++ "b/C:\\Users\\crist\\Documents\\nerfstudio_custom\\Extra-Methods-Patches\\zipnerf-pytorch\\extensions\\cuda\\setup.py" +@@ -16,6 +16,7 @@ if os.name == "nt": + + def find_cl_path(): + import glob ++ + for edition in ["Enterprise", "Professional", "BuildTools", "Community"]: + paths = sorted( + glob.glob( diff --git a/Extra-Methods-Patches/zipnerf-pytorch/make_patch_zipnerf_cuda.bat b/Extra-Methods-Patches/zipnerf-pytorch/make_patch_zipnerf_cuda.bat new file mode 100644 index 0000000000..d3558ef446 --- /dev/null +++ b/Extra-Methods-Patches/zipnerf-pytorch/make_patch_zipnerf_cuda.bat @@ -0,0 +1,55 @@ +@echo off +setlocal EnableExtensions + +REM Script lives in Extra-Methods-Patches\zipnerf-pytorch +cd /d "%~dp0" +set "PATCH_ROOT=%CD%" + +REM Go up to nerfstudio_custom root +cd /d "%PATCH_ROOT%\..\.." +set "ROOT_DIR=%CD%" + +REM Paths +set "ORIG_FILE=%ROOT_DIR%\zipnerf-pytorch\extensions\cuda\setup.py" +set "PATCHED_FILE=%PATCH_ROOT%\extensions\cuda\setup.py" +set "PATCH_FILE=%PATCH_ROOT%\extensions\cuda\setup.py.patch" + +REM Checks +if not exist "%ORIG_FILE%" ( + echo [ERROR] Original file not found: + echo %ORIG_FILE% + exit /b 1 +) + +if not exist "%PATCHED_FILE%" ( + echo [ERROR] Patched file not found: + echo %PATCHED_FILE% + exit /b 1 +) + +where git >nul 2>nul +if errorlevel 1 ( + echo [ERROR] git not found in PATH + exit /b 1 +) + +echo [INFO] Generating patch... +git diff --no-index "%ORIG_FILE%" "%PATCHED_FILE%" > "%PATCH_FILE%" +set "RC=%errorlevel%" + +if "%RC%"=="0" ( + echo [INFO] No differences found + echo [INFO] Patch file still written: + echo %PATCH_FILE% + exit /b 0 +) + +if "%RC%"=="1" ( + echo [OK] Patch created: + echo %PATCH_FILE% + exit /b 0 +) + +echo [ERROR] git diff failed with code %RC% +del /q "%PATCH_FILE%" >nul 2>nul +exit /b %RC% \ No newline at end of file diff --git a/Extra-Methods-Patches/zipnerf-pytorch/make_patch_zipnerf_cuda.sh b/Extra-Methods-Patches/zipnerf-pytorch/make_patch_zipnerf_cuda.sh new file mode 100644 index 0000000000..bee101ce9d --- /dev/null +++ b/Extra-Methods-Patches/zipnerf-pytorch/make_patch_zipnerf_cuda.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env sh +set -eu + +# Script dir = Extra-Methods-Patches/zipnerf-pytorch +PATCH_ROOT=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) + +# Go up to nerfstudio_custom root +ROOT_DIR=$(CDPATH= cd -- "$PATCH_ROOT/../.." && pwd) + +ORIG_FILE="$ROOT_DIR/zipnerf-pytorch/extensions/cuda/setup.py" +PATCHED_FILE="$PATCH_ROOT/extensions/cuda/setup.py" +PATCH_FILE="$PATCH_ROOT/extensions/cuda/setup.py.patch" + +if [ ! -f "$ORIG_FILE" ]; then + echo "[ERROR] Original file not found:" + echo " $ORIG_FILE" + exit 1 +fi + +if [ ! -f "$PATCHED_FILE" ]; then + echo "[ERROR] Patched file not found:" + echo " $PATCHED_FILE" + exit 1 +fi + +if ! command -v git >/dev/null 2>&1; then + echo "[ERROR] git not found in PATH" + exit 1 +fi + +echo "[INFO] Generating patch..." +set +e +git diff --no-index "$ORIG_FILE" "$PATCHED_FILE" > "$PATCH_FILE" +RC=$? +set -e + +if [ "$RC" -eq 0 ]; then + echo "[INFO] No differences found" + echo "[INFO] Patch file still written:" + echo " $PATCH_FILE" + exit 0 +fi + +if [ "$RC" -eq 1 ]; then + echo "[OK] Patch created:" + echo " $PATCH_FILE" + exit 0 +fi + +echo "[ERROR] git diff failed with code $RC" +rm -f "$PATCH_FILE" +exit "$RC" \ No newline at end of file diff --git a/Extra-Methods-Patches/zipnerf-pytorch/zipnerf_ns/zipnerf_config.py b/Extra-Methods-Patches/zipnerf-pytorch/zipnerf_ns/zipnerf_config.py new file mode 100644 index 0000000000..54bb31f18d --- /dev/null +++ b/Extra-Methods-Patches/zipnerf-pytorch/zipnerf_ns/zipnerf_config.py @@ -0,0 +1,58 @@ +""" +Nerfstudio ZipNerf Config + +Define your custom method here that registers with Nerfstudio CLI. +""" + +from __future__ import annotations + +from nerfstudio.configs.base_config import ViewerConfig +from nerfstudio.engine.optimizers import AdamOptimizerConfig +from nerfstudio.engine.schedulers import ExponentialDecaySchedulerConfig +from nerfstudio.engine.trainer import TrainerConfig +from nerfstudio.plugins.types import MethodSpecification + +from zipnerf_ns.zipnerf_datamanager import ZipNerfDataManagerConfig +from zipnerf_ns.zipnerf_model import ZipNerfModelConfig +from zipnerf_ns.zipnerf_pipeline import ZipNerfPipelineConfig + + +zipnerf_method = MethodSpecification( + config=TrainerConfig( + method_name="zipnerf", + steps_per_eval_batch=1000, + steps_per_eval_image=5000, + steps_per_save=5000, + max_num_iterations=25000, + mixed_precision=True, + log_gradients=False, + pipeline=ZipNerfPipelineConfig( + datamanager=ZipNerfDataManagerConfig( + train_num_rays_per_batch=8192, + eval_num_rays_per_batch=8192, + ), + model=ZipNerfModelConfig( + eval_num_rays_per_chunk=1 << 15, + gin_file=["configs/360.gin"], + proposal_weights_anneal_max_num_iters=1000, + ), + ), + optimizers={ + "model": { + "optimizer": AdamOptimizerConfig(lr=8e-3, eps=1e-15), + "scheduler": ExponentialDecaySchedulerConfig( + warmup_steps=1000, + lr_final=1e-3, + max_steps=25000, + ), + } + }, + viewer=ViewerConfig(num_rays_per_chunk=1 << 15), + vis="viewer", + ), + description=( + "An unofficial pytorch implementation of " + "'Zip-NeRF: Anti-Aliased Grid-Based Neural Radiance Fields' " + "https://arxiv.org/abs/2304.06706." + ), +) \ No newline at end of file diff --git a/Extra-Methods-Patches/zipnerf-pytorch/zipnerf_ns/zipnerf_datamanager.py b/Extra-Methods-Patches/zipnerf-pytorch/zipnerf_ns/zipnerf_datamanager.py new file mode 100644 index 0000000000..706bdd272b --- /dev/null +++ b/Extra-Methods-Patches/zipnerf-pytorch/zipnerf_ns/zipnerf_datamanager.py @@ -0,0 +1,86 @@ +""" +ZipNerf DataManager +""" + +from dataclasses import dataclass, field +from typing import Dict, Literal, Tuple, Type, Union + +import torch + +from nerfstudio.cameras.rays import RayBundle +from nerfstudio.data.datamanagers.base_datamanager import ( + VanillaDataManager, + VanillaDataManagerConfig, +) +from nerfstudio.data.dataparsers.colmap_dataparser import ColmapDataParserConfig + + +@dataclass +class ZipNerfDataManagerConfig(VanillaDataManagerConfig): + """ZipNerf DataManager Config.""" + + _target: Type = field(default_factory=lambda: ZipNerfDataManager) + + # Important: + # use a concrete dataparser type here, not AnnotatedDataParserUnion. + # This avoids Tyro subcommand matching failures on Windows / newer tyro. + dataparser: ColmapDataParserConfig = field( + default_factory=lambda: ColmapDataParserConfig( + downscale_factor=4, + orientation_method="up", + center_method="poses", + colmap_path="sparse/0", + ) + ) + + +class ZipNerfDataManager(VanillaDataManager): + """ZipNerf DataManager""" + + config: ZipNerfDataManagerConfig + + def __init__( + self, + config: ZipNerfDataManagerConfig, + device: Union[torch.device, str] = "cpu", + test_mode: Literal["test", "val", "inference"] = "val", + world_size: int = 1, + local_rank: int = 0, + **kwargs, + ): + super().__init__( + config=config, + device=device, + test_mode=test_mode, + world_size=world_size, + local_rank=local_rank, + **kwargs, + ) + + def next_train(self, step: int) -> Tuple[RayBundle, Dict]: + """Returns the next batch of data from the train dataloader.""" + self.train_count += 1 + image_batch = next(self.iter_train_image_dataloader) + assert self.train_pixel_sampler is not None + assert isinstance(image_batch, dict) + + batch = self.train_pixel_sampler.sample(image_batch) + batch["rgb"] = batch["image"].to(self.device) + + ray_indices = batch["indices"] + ray_bundle = self.train_ray_generator(ray_indices) + return ray_bundle, batch + + def next_eval(self, step: int) -> Tuple[RayBundle, Dict]: + """Returns the next batch of data from the eval dataloader.""" + self.eval_count += 1 + image_batch = next(self.iter_eval_image_dataloader) + assert self.eval_pixel_sampler is not None + assert isinstance(image_batch, dict) + + batch = self.eval_pixel_sampler.sample(image_batch) + batch["rgb"] = batch["image"].to(self.device) + + ray_indices = batch["indices"] + ray_bundle = self.eval_ray_generator(ray_indices) + return ray_bundle, batch \ No newline at end of file diff --git a/INSTALL_NOTES.md b/INSTALL_NOTES.md new file mode 100644 index 0000000000..4775e49710 --- /dev/null +++ b/INSTALL_NOTES.md @@ -0,0 +1,15 @@ +# Nerfstudio Custom installer notes + +## What changed +- Removed hardcoded absolute paths for CUDA, Visual Studio, and Conda prefixes. +- Added prompts for new or existing environments instead of forcing a fixed env name. +- Added package flavor selection (`base`, `gen`, `dev`, `dev,docs`). +- Added safer CUDA/Torch presets that follow the Nerfstudio installation guide. +- Split optional methods from the base installer. +- Added a separate helper flow for SDFStudio / Neuralangelo instead of mixing them into the main Nerfstudio env. + +## Why keep SDFStudio / Neuralangelo separate +SDFStudio still documents an older environment target and says it was tested with Python 3.8, Torch 1.12.1 + CUDA 11.3, plus tiny-cuda-nn. It also exposes Neuralangelo support inside the SDFStudio codebase. Mixing that into a modern Nerfstudio 1.1.x environment is likely to create version conflicts. + +## Docker note +Your Docker build likely needs to be split or slimmed down. Right now the Dockerfile builds GLOMAP, COLMAP, tiny-cuda-nn, HLOC, gsplat, and Nerfstudio in one GH Actions job, which is expensive for the default runner budget. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index ee561dfbe4..0000000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2023 The Nerfstudio Team - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/README_FULL.md b/README_FULL.md index 25a213d3f0..ea47df9e22 100644 --- a/README_FULL.md +++ b/README_FULL.md @@ -1,3 +1,253 @@ install nerfstudio via base.bat Conda or python venv(experimental) -install extra nerfstudio algorythms via extras.bat +install extra nerfstudio algorythms via extras_portable_manager.bat validate the installed and available algorythms with test_cli.py + +NEW: + +Nerfstudio Custom – Installation Prerequisites (Windows) + +Before running the installer, you must install the required toolchains manually. +The installer assumes these are already present and correctly configured. + +1. Install Anaconda (Required) + +Download and install Anaconda (Python distribution) from the official source: + +👉 https://www.anaconda.com/download + +Notes: + +Install for your user (recommended) + +Make sure conda works from terminal: + +conda --version + +Do NOT rely on system Python — the installer will manage environments via Conda + +2. Install CUDA Toolkit 11.8 (Required for GPU) + +Download CUDA 11.8 specifically (do NOT install newer versions for this setup): + +👉 https://developer.nvidia.com/cuda-11-8-0-download-archive + +Important: + +Choose: + +Windows → x86_64 → your OS → exe (local) + +Install with default settings + +After install, verify: + +nvcc --version +Expected path (default): +C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8 +3. Install Visual Studio Build Tools (Required) + +You need MSVC for compiling native extensions. + +👉 https://visualstudio.microsoft.com/downloads/ + +Install: + +Build Tools for Visual Studio 2022 + +Required components: + +✔ Desktop development with C++ + +✔ MSVC v143 toolset + +✔ Windows 10/11 SDK + +4. Install ROCm HIP SDK (Optional but Recommended) + +Even if you're using NVIDIA, some builds probe for ROCm/HIP. + +Download from official AMD source: + +👉 https://www.amd.com/en/developer/resources/rocm-hub/hip-sdk.html + +Notes: + +Install default configuration + +The installer will disable HIP/ROCm automatically during builds + +This avoids PyTorch extension conflicts on Windows + +5. Environment Variables (Handled by Installer) + +You DO NOT need to manually set: + +CUDA_HOME + +CUDA_PATH + +CUB_HOME + +The installer will: + +detect your paths + +convert them to short (8.3) paths + +override them locally when needed (e.g. for tiny-cuda-nn) + +6. After Prerequisites + +Once everything is installed, run: + +install_windows_all_in_one.bat + +The installer will: + +create or use a Conda environment + +install Nerfstudio + dependencies + +align Torch + CUDA versions + +build native modules (tiny-cuda-nn, gsplat, etc.) + +store built wheels in: + +./wheelhouse +⚠️ Common Pitfalls +Wrong CUDA version + +Must be 11.8 + +Newer versions (12.x) will break builds + +Missing MSVC + +If cl.exe is missing → installs will fail + +Conflicting environment variables + +System-level CUDA_PATH pointing to another version (e.g. 12.8) + +The installer overrides this, but misconfigurations can still leak + +✅ Recommended Setup Summary +Component Version +Python (Conda) 3.10 +CUDA Toolkit 11.8 +PyTorch 2.1.2 + cu118 +Torchvision 0.16.2 +MSVC VS 2022 +# Nerfstudio Custom + +A custom Nerfstudio fork focused on improved Windows installation support and optional extra NeRF methods. + +## Windows prerequisites + +Install these manually before running the installer: + +### 1. Anaconda +Download and install from the official source: +- https://www.anaconda.com/download + +### 2. CUDA Toolkit 11.8 +Use CUDA **11.8** for the recommended Windows stack. +- https://developer.nvidia.com/cuda-11-8-0-download-archive + +### 3. Visual Studio 2022 C++ Build Tools +Install: +- Desktop development with C++ +- MSVC v143 +- Windows 10/11 SDK + +For best compatibility with CUDA 11.8, also install the **14.38** MSVC toolset if available. + +### 4. AMD HIP SDK / ROCm for Windows +Optional, official source: +- https://www.amd.com/en/developer/resources/rocm-hub/hip-sdk.html + +If HIP/ROCm is installed, it may need to be temporarily hidden during some NVIDIA/CUDA extension builds. + +--- + +## Recommended Windows stack + +- Python 3.10 +- Torch 2.1.2 + cu118 +- Torchvision 0.16.2 + cu118 +- CUDA Toolkit 11.8 +- Visual Studio 2022 with MSVC 14.38 preferred + +--- + +## Base install + +Run the Windows all-in-one installer from the repo root. + +It will: +- create or reuse a Python environment +- install Nerfstudio +- align Torch/CUDA versions +- cache wheels in `wheelhouse` +- optionally install extra modules + +--- + +## Important compatibility notes + +### NumPy +Keep an eye on NumPy version drift. + +Some plugins still work best with: +- `numpy<2.0` + +But newer OpenCV wheels may try to force: +- `numpy>=2` + +If plugin installs upgrade NumPy unexpectedly, re-check compatibility before continuing. + +### Torch / CUDA +Do not let plugin-specific requirements replace the stable base stack unless you are intentionally testing a separate environment. + +Recommended stable pair: +- `torch==2.1.2+cu118` +- `torchvision==0.16.2+cu118` + +--- + +## Extra methods and plugin notes + +## Zip-NeRF on Windows + +This plugin is experimental on Windows and needs a few manual fixes. + +### 1. Keep the stable Nerfstudio stack +Use the same stack as the base installer: + +- Python 3.10 +- Torch 2.1.2 + cu118 +- Torchvision 0.16.2 + cu118 +- CUDA Toolkit 11.8 +- MSVC 14.38 / VS2022 C++ tools + +Do not let `zipnerf-pytorch/requirements.txt` replace: +- torch +- torchvision +- numpy +- opencv-python +- opencv-contrib-python + +Those upgrades can break the Nerfstudio environment. + +### 2. Build the CUDA extension without build isolation +The extension imports `torch` during build, so install it with: + +```bat +python -m pip install --no-build-isolation .\extensions\cuda + +## Instruct-GS2GS / IGS2GS on Windows + +If CLI issues appear, pin: +```bat +pip install tyro==0.8.12 diff --git a/auto_install_missing_methods.py b/auto_install_missing_methods.py new file mode 100644 index 0000000000..1626f7a43e --- /dev/null +++ b/auto_install_missing_methods.py @@ -0,0 +1,52 @@ +import subprocess +import sys +import re + +ROOT = "C:/Users/crist/Documents/nerfstudio_custom" + +def run_cmd(cmd): + return subprocess.run(cmd, shell=True, capture_output=True, text=True) + +def try_ns(): + result = run_cmd("ns-viewer --help") + return result.stderr + result.stdout + +def install_module(module_name): + print(f"[AUTO] Trying to install: {module_name}") + + import os + + for folder in os.listdir(ROOT): + path = os.path.join(ROOT, folder) + if os.path.isdir(path): + if module_name.lower() in folder.lower(): + print(f"[FOUND] Installing from {folder}") + subprocess.run(f'cd "{path}" && pip install -e . --no-deps', shell=True) + return True + + print(f"[MISS] Could not find folder for {module_name}") + return False + + +def main(): + for _ in range(10): + output = try_ns() + + match = re.search(r"No module named '([^']+)'", output) + if not match: + print("✅ All dependencies resolved") + return + + missing = match.group(1).split(".")[0] + print(f"[MISSING] {missing}") + + ok = install_module(missing) + if not ok: + print("❌ Could not resolve automatically") + return + + print("⚠️ Too many iterations") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/base.bat b/base.bat deleted file mode 100644 index a06a7e1930..0000000000 --- a/base.bat +++ /dev/null @@ -1,50 +0,0 @@ -@echo off -setlocal enabledelayedexpansion - -REM ==== CONFIG ==== -set ENV_NAME=nerfstudio -set YAML_FILE=requirements_conda.yaml -set REQUIREMENTS=requirements_pip.txt -set PYTHON_EXE=python - -echo. -echo === Nerfstudio Base Installer === -echo. - -REM === Choose install mode === -choice /C CVP /M "Choose environment type: (C)onda, (V)env, or (P)reinstalled python?" -if errorlevel 3 set INSTALL_MODE=PYTHON -if errorlevel 2 set INSTALL_MODE=VENV -if errorlevel 1 set INSTALL_MODE=CONDA - -REM === Setup environment === -if "%INSTALL_MODE%"=="CONDA" ( - choice /C YN /M "Use YAML file? (Y=yes, N=use requirements.txt)" - if errorlevel 2 ( - echo Creating conda env from pip reqs... - conda create -y -n %ENV_NAME% python=3.10 - call conda activate %ENV_NAME% - pip install -r %REQUIREMENTS% - ) else ( - echo Creating conda env from YAML... - conda env create -f %YAML_FILE% - call conda activate %ENV_NAME% - ) -) else if "%INSTALL_MODE%"=="VENV" ( - echo Creating venv... - %PYTHON_EXE% -m venv %ENV_NAME% - call %ENV_NAME%\Scripts\activate - pip install -r %REQUIREMENTS% -) else ( - echo Using system-installed Python... - pip install -r %REQUIREMENTS% -) - -REM === Nerfstudio CLI === -pip install nerfstudio -call ns-install-cli - -echo. -echo ✅ Base Nerfstudio environment ready. -echo Run extras.bat to install optional modules. -pause diff --git a/check_tetranerf_modules.py b/check_tetranerf_modules.py new file mode 100644 index 0000000000..86ec87dc2f --- /dev/null +++ b/check_tetranerf_modules.py @@ -0,0 +1,26 @@ +import importlib + +mods = [ + "tetranerf.nerfstudio.config", + "tetranerf.nerfstudio.method", + "tetranerf.nerfstudio.tetra_nerf", + "tetranerf.nerfstudio.dataparser", + "tetranerf.nerfstudio.tetranerf", + # aggiungiamo anche quelli che hai visto esistere + "tetranerf.nerfstudio.model", + "tetranerf.nerfstudio.pipeline", + "tetranerf.nerfstudio.registration", +] + +print("=== Tetra-NeRF module probe ===\n") + +for m in mods: + try: + x = importlib.import_module(m) + print(f"[OK] {m}") + print(f" -> {getattr(x, '__file__', None)}\n") + except Exception as e: + print(f"[NO] {m}") + print(f" -> {e}\n") + +print("=== done ===") \ No newline at end of file diff --git a/clone_missing_methods.bat b/clone_missing_methods.bat new file mode 100644 index 0000000000..92a9438d7c --- /dev/null +++ b/clone_missing_methods.bat @@ -0,0 +1,52 @@ +@echo off +set ROOT=%CD% + +echo ============================== +echo Cloning missing Nerfstudio methods +echo ============================== + +REM ---- splatfacto-w ---- +if not exist "%ROOT%\splatfacto-w" ( + echo Cloning splatfacto-w... + git clone https://github.com/your-fork/splatfacto-w.git +) + +REM ---- zipnerf ---- +if not exist "%ROOT%\zipnerf-pytorch" ( + echo Cloning zipnerf-pytorch... + git clone https://github.com/SuLvXiangXin/zipnerf-pytorch.git +) + +REM ---- instruct-gs2gs ---- +if not exist "%ROOT%\instruct-gs2gs" ( + echo Cloning instruct-gs2gs... + git clone https://github.com/ashawkey/instruct-gs2gs.git +) + +REM ---- tetra-nerf ---- +if not exist "%ROOT%\tetra-nerf" ( + echo Cloning tetra-nerf... + git clone https://github.com/jkulhanek/tetra-nerf.git +) + +REM ---- opennerf ---- +if not exist "%ROOT%\opennerf" ( + echo Cloning opennerf... + git clone https://github.com/opennerf/opennerf.git +) + +REM ---- OPTIONAL / PRESENT IN YOUR ROOT ---- + +if not exist "%ROOT%\sdfstudio" ( + echo Cloning sdfstudio... + git clone https://github.com/autonomousvision/sdfstudio.git +) + +if not exist "%ROOT%\relationfield" ( + echo Cloning relationfield... + git clone https://github.com/nerfstudio-project/relationfield.git +) + +echo. +echo ✅ Clone step completed +pause \ No newline at end of file diff --git a/debug_tetranerf_geometry.py b/debug_tetranerf_geometry.py new file mode 100644 index 0000000000..13f4e4259f --- /dev/null +++ b/debug_tetranerf_geometry.py @@ -0,0 +1,415 @@ +import argparse +import math +import sys +from pathlib import Path + +import torch + +# Nerfstudio / Tetra-NeRF imports +from tetranerf.nerfstudio.registration import tetranerf_config +from tetranerf.utils.extension import TetrahedraTracer, triangulate + + +def qstats(x: torch.Tensor, name: str) -> None: + x = x.detach().reshape(-1).float().cpu() + finite = torch.isfinite(x) + x = x[finite] + if x.numel() == 0: + print(f"[{name}] no finite values") + return + qs = torch.tensor([0.0, 0.001, 0.01, 0.05, 0.25, 0.5, 0.75, 0.95, 0.99, 0.999, 1.0]) + vals = torch.quantile(x, qs) + print(f"\n[{name}]") + for q, v in zip(qs.tolist(), vals.tolist()): + print(f" q={q:>6.3f}: {v:.8g}") + print(f" mean : {x.mean().item():.8g}") + print(f" std : {x.std().item():.8g}") + print(f" count : {x.numel()}") + +def inspect_model_tetra_vertices(pipeline): + print("\n=== MODEL TETRA VERTICES ===") + verts = pipeline.model.tetrahedra_vertices.detach().cpu() + bbox_stats(verts, "model_tetrahedra_vertices") + +def bbox_stats(points: torch.Tensor, name: str) -> None: + pts = points.detach().reshape(-1, 3).float().cpu() + finite = torch.isfinite(pts).all(dim=-1) + pts = pts[finite] + if pts.numel() == 0: + print(f"[{name}] no finite points") + return + mins = pts.min(dim=0).values + maxs = pts.max(dim=0).values + ctr = pts.mean(dim=0) + ext = maxs - mins + print(f"\n[{name}]") + print(f" min : {mins.tolist()}") + print(f" max : {maxs.tolist()}") + print(f" center : {ctr.tolist()}") + print(f" extent : {ext.tolist()}") + qstats(torch.linalg.norm(pts - ctr, dim=-1), f"{name}/distance_from_mean") + + +def apply_transform_and_scale(points: torch.Tensor, dataparser_transform: torch.Tensor, dataparser_scale: float) -> torch.Tensor: + """ + points: [N,3] + dataparser_transform: expected [3,4] or [4,4] + """ + pts = points.float() + tf = dataparser_transform.float().cpu() + + if tf.shape == (3, 4): + R = tf[:, :3] + t = tf[:, 3] + elif tf.shape == (4, 4): + R = tf[:3, :3] + t = tf[:3, 3] + else: + raise ValueError(f"Unexpected dataparser_transform shape: {tuple(tf.shape)}") + + out = (pts @ R.T) + t + out = out * float(dataparser_scale) + return out + + +def camera_centers_from_c2w(camera_to_worlds: torch.Tensor) -> torch.Tensor: + """ + camera_to_worlds: [N,3,4] or [N,4,4] + """ + c2w = camera_to_worlds.float().cpu() + if c2w.shape[-2:] == (3, 4): + return c2w[..., :3, 3] + if c2w.shape[-2:] == (4, 4): + return c2w[..., :3, 3] + raise ValueError(f"Unexpected camera_to_worlds shape: {tuple(c2w.shape)}") + + +def tetra_volumes(vertices: torch.Tensor, cells: torch.Tensor) -> torch.Tensor: + """ + vertices: [V,3] + cells: [T,4] + returns [T] + """ + v = vertices[cells.long()] # [T,4,3] + a = v[:, 1] - v[:, 0] + b = v[:, 2] - v[:, 0] + c = v[:, 3] - v[:, 0] + vol6 = torch.abs(torch.sum(torch.cross(a, b, dim=-1) * c, dim=-1)) + return vol6 / 6.0 + + +def build_pipeline(data_path: str, device: str): + cfg = tetranerf_config + + # Clone-ish behavior without mutating global registration permanently + import copy + cfg = copy.deepcopy(cfg) + + cfg.machine.device_type = "cuda" + cfg.pipeline.datamanager.data = Path(data_path) + cfg.vis = "viewer" # keep current known-good mode + cfg.logging.local_writer.enable = False # reduce noise if present + + pipeline = cfg.pipeline.setup( + device=device, + test_mode="val", + world_size=1, + local_rank=0, + grad_scaler=None, + ) + return cfg, pipeline + + +def get_sparse_points_cpu(pipeline): + """ + Tries several likely places where COLMAP / dataparser points may live. + """ + dpo = pipeline.datamanager.train_dataparser_outputs + + candidates = [] + + # Common nerfstudio metadata locations + if hasattr(dpo, "metadata") and isinstance(dpo.metadata, dict): + md = dpo.metadata + for key in ["points3D_xyz", "points3D", "points_xyz", "point_cloud_xyz"]: + if key in md: + candidates.append((f"train_dataparser_outputs.metadata['{key}']", md[key])) + + ds = pipeline.datamanager.train_dataset + if hasattr(ds, "metadata") and isinstance(ds.metadata, dict): + md = ds.metadata + for key in ["points3D_xyz", "points3D", "points_xyz", "point_cloud_xyz"]: + if key in md: + candidates.append((f"train_dataset.metadata['{key}']", md[key])) + + for name, value in candidates: + if isinstance(value, torch.Tensor) and value.ndim == 2 and value.shape[-1] == 3: + return name, value.detach().cpu().float() + + raise RuntimeError( + "Could not find sparse points in known metadata locations. " + "Print pipeline.datamanager.train_dataparser_outputs.metadata keys and " + "train_dataset.metadata keys, then adapt this helper." + ) + + +def print_metadata_keys(pipeline): + dpo = pipeline.datamanager.train_dataparser_outputs + print("\n[metadata keys]") + if hasattr(dpo, "metadata") and isinstance(dpo.metadata, dict): + print(" train_dataparser_outputs.metadata keys:", sorted(dpo.metadata.keys())) + else: + print(" train_dataparser_outputs.metadata: unavailable") + + ds = pipeline.datamanager.train_dataset + if hasattr(ds, "metadata") and isinstance(ds.metadata, dict): + print(" train_dataset.metadata keys:", sorted(ds.metadata.keys())) + else: + print(" train_dataset.metadata: unavailable") + + +def inspect_transform_consistency(pipeline): + dpo = pipeline.datamanager.train_dataparser_outputs + cams = pipeline.datamanager.train_dataset.cameras + + print("\n=== TRANSFORM CONSISTENCY ===") + print(f"dataparser_scale = {float(dpo.dataparser_scale)}") + print(f"dataparser_transform shape = {tuple(dpo.dataparser_transform.shape)}") + + camera_centers = camera_centers_from_c2w(cams.camera_to_worlds) + bbox_stats(camera_centers, "camera_centers") + + src_name, sparse_points = get_sparse_points_cpu(pipeline) + print(f"sparse points source: {src_name}") + bbox_stats(sparse_points, "sparse_points/raw") + + transformed_points = apply_transform_and_scale( + sparse_points, + dpo.dataparser_transform, + float(dpo.dataparser_scale), + ) + bbox_stats(transformed_points, "sparse_points/transformed") + + cam_center = camera_centers.mean(dim=0) + raw_center = sparse_points.mean(dim=0) + transformed_center = transformed_points.mean(dim=0) + + print("\n[center distances]") + print(" ||camera_mean - raw_points_mean|| =", torch.linalg.norm(cam_center - raw_center).item()) + print(" ||camera_mean - transformed_points_mean|| =", torch.linalg.norm(cam_center - transformed_center).item()) + + return sparse_points, transformed_points + + +def inspect_tetra_quality(points_for_tetra: torch.Tensor, max_points_for_cpu_triangulation: int = 120_000): + print("\n=== TETRA QUALITY ===") + n = points_for_tetra.shape[0] + print(f"num input points = {n}") + + if n > max_points_for_cpu_triangulation: + print(f"Too many points for a quick debug triangulation ({n} > {max_points_for_cpu_triangulation}).") + print("Subsampling for diagnostics...") + idx = torch.randperm(n)[:max_points_for_cpu_triangulation] + pts = points_for_tetra[idx].contiguous() + else: + pts = points_for_tetra.contiguous() + + print(f"triangulating {pts.shape[0]} points...") + cells = triangulate(pts) # returns int32 on same device as input; CPU input is fine too + if cells.is_cuda: + cells = cells.cpu() + cells = cells.contiguous().int() + + print(f"num tetrahedra = {cells.shape[0]}") + vols = tetra_volumes(pts.cpu(), cells.cpu()) + qstats(vols, "tetra_volumes") + + large_idx = torch.argsort(vols, descending=True)[:10] + print("\n[top 10 tetra volumes]") + for rank, i in enumerate(large_idx.tolist(), start=1): + tet = cells[i].tolist() + print(f" #{rank:02d}: vol={vols[i].item():.8g}, cell={tet}") + + return pts.cpu(), cells.cpu(), vols.cpu() + + +def inspect_outliers(points: torch.Tensor): + print("\n=== OUTLIER CHECK ===") + center = points.mean(dim=0, keepdim=True) + d = torch.linalg.norm(points - center, dim=-1) + qstats(d, "point_distance_from_mean") + + q99 = torch.quantile(d, 0.99) + q999 = torch.quantile(d, 0.999) + + keep_99 = d <= q99 + keep_999 = d <= q999 + + print(f"keep <= q99 : {keep_99.sum().item()} / {points.shape[0]}") + print(f"keep <= q999 : {keep_999.sum().item()} / {points.shape[0]}") + + return keep_99, keep_999 + + +def inspect_find_tetrahedra(points_for_tetra: torch.Tensor, cells: torch.Tensor, device: str): + print("\n=== FIND_TETRAHEDRA SANITY ===") + + xyz = points_for_tetra.to(device=device, dtype=torch.float32).contiguous() + cells_gpu = cells.to(device=device, dtype=torch.int32).contiguous() + + tracer = TetrahedraTracer(torch.device(device)) + tracer.load_tetrahedra(xyz, cells_gpu) + + # Test with tetra centroids: these should be inside their own tetrahedra. + tet_vertices = xyz[cells_gpu.long()] # [T,4,3] + centroids = tet_vertices.mean(dim=1) # [T,3] + + max_test = min(2048, centroids.shape[0]) + centroids = centroids[:max_test].contiguous() + + result = tracer.find_tetrahedra(centroids) + tetrahedra = result["tetrahedra"].detach().cpu() + bary = result["barycentric_coordinates"].detach().cpu() + valid = result["valid_mask"].detach().cpu() + + valid_rate = valid.float().mean().item() + print(f"valid centroid rate = {valid_rate:.6f}") + + if valid.any(): + bary_sum = bary[valid].sum(dim=-1) + qstats(bary_sum, "centroid_bary_sum") + qstats(bary[valid].reshape(-1), "centroid_bary_values") + + matched_self = (tetrahedra[valid] == torch.arange(max_test, dtype=tetrahedra.dtype)[valid]).float().mean().item() if valid.any() else float("nan") + print(f"matched original tetra rate = {matched_self:.6f}") + + return tracer + +def inspect_ray_trace_from_train_batch(pipeline, tracer, max_rays: int = 256, max_ray_triangles: int = 256): + print("\n=== TRACE_RAYS SANITY (FROM TRAIN BATCH) ===") + + ray_bundle, batch = pipeline.datamanager.next_train(0) + + ray_origins = ray_bundle.origins.reshape(-1, 3).contiguous().float() + ray_dirs = ray_bundle.directions.reshape(-1, 3).contiguous().float() + + if ray_origins.shape[0] > max_rays: + ray_origins = ray_origins[:max_rays] + ray_dirs = ray_dirs[:max_rays] + + print("ray_origins shape:", tuple(ray_origins.shape), ray_origins.dtype, ray_origins.device) + print("ray_dirs shape :", tuple(ray_dirs.shape), ray_dirs.dtype, ray_dirs.device) + print("max_ray_triangles:", max_ray_triangles) + + result = tracer.trace_rays(ray_origins, ray_dirs, max_ray_triangles) + + num_visited = result["num_visited_cells"].detach().cpu() + visited = result["visited_cells"].detach().cpu() + bary = result["barycentric_coordinates"].detach().cpu() + hit_d = result["hit_distances"].detach().cpu() + v_idx = result["vertex_indices"].detach().cpu() + + qstats(num_visited.float(), "num_visited_cells_per_ray") + + used = num_visited > 0 + print(f"rays with intersections = {used.sum().item()} / {num_visited.numel()}") + + if used.any(): + first_counts = num_visited[used] + print(f"mean visited cells over hit rays = {first_counts.float().mean().item():.4f}") + + first_hit = hit_d[used, 0] + qstats(first_hit.reshape(-1), "first_hit_distances_flat") + qstats((first_hit[:, 1] - first_hit[:, 0]), "first_hit_interval_length") + + first_bary = bary[used, 0] + qstats(first_bary.reshape(-1), "first_hit_bary_values") + + print("\n[sample first few rays]") + hit_rows = torch.nonzero(used, as_tuple=False).squeeze(-1) + for j in range(min(8, hit_rows.numel())): + i = hit_rows[j].item() + print( + f" ray {i}: visited={int(num_visited[i])}, " + f"first_cell={int(visited[i, 0])}, " + f"first_hit={hit_d[i, 0].tolist()}, " + f"first_vertex_idx={v_idx[i, 0].tolist()}" + ) + +def try_model_forward_stats(pipeline): + print("\n=== MODEL FORWARD STATS (BEST EFFORT) ===") + try: + ray_bundle, batch = pipeline.datamanager.next_train(0) + outputs = pipeline.model(ray_bundle) + + for key in ["rgb", "depth", "accumulation"]: + if key in outputs and isinstance(outputs[key], torch.Tensor): + qstats(outputs[key], f"model_output/{key}") + + except Exception as exc: + print(f"Could not run model forward stats: {exc}") + +def print_largest_tetra_vertices(points: torch.Tensor, cells: torch.Tensor, vols: torch.Tensor, topk: int = 10): + print("\n=== LARGEST TETRA VERTICES ===") + idx = torch.argsort(vols, descending=True)[:topk] + for rank, i in enumerate(idx.tolist(), start=1): + tet = cells[i].long() + verts = points[tet] + center = verts.mean(dim=0) + print(f"\n#{rank:02d} tetra index={i} vol={vols[i].item():.8g}") + print(f" cell indices: {tet.tolist()}") + print(f" center : {center.tolist()}") + for j in range(4): + print(f" v{j}: {verts[j].tolist()}") + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--data", type=str, required=True, help="Path to dataset dense/ root") + parser.add_argument("--device", type=str, default="cuda:0") + parser.add_argument("--max-points-for-cpu-triangulation", type=int, default=120000) + args = parser.parse_args() + + torch.set_grad_enabled(False) + + print("Building pipeline...") + cfg, pipeline = build_pipeline(args.data, args.device) + + inspect_model_tetra_vertices(pipeline) + + print_metadata_keys(pipeline) + + sparse_raw, sparse_transformed = inspect_transform_consistency(pipeline) + + keep_99, keep_999 = inspect_outliers(sparse_transformed) + + # Main tetra diagnostic on the actual model tetra vertices + model_pts = pipeline.model.tetrahedra_vertices.detach().cpu() + + pts_cpu, cells_cpu, vols = inspect_tetra_quality( + model_pts, + max_points_for_cpu_triangulation=args.max_points_for_cpu_triangulation, + ) + + print("\n=== OPTIONAL REPEAT: FILTERED POINTS (q99) ===") + model_center = model_pts.mean(dim=0, keepdim=True) + model_d = torch.linalg.norm(model_pts - model_center, dim=-1) + model_q99 = torch.quantile(model_d, 0.99) + filtered_pts = model_pts[model_d <= model_q99] + if filtered_pts.shape[0] >= 16: + inspect_tetra_quality( + filtered_pts, + max_points_for_cpu_triangulation=min(args.max_points_for_cpu_triangulation, filtered_pts.shape[0]), + ) + else: + print("Not enough points after filtering.") + + tracer = inspect_find_tetrahedra(pts_cpu, cells_cpu, args.device) + inspect_ray_trace_from_train_batch(pipeline, tracer) + try_model_forward_stats(pipeline) + print_largest_tetra_vertices(pts_cpu, cells_cpu, vols, topk=10) + + print("\nDONE.") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/deps-lock/.tmp-bulk-install.txt b/deps-lock/.tmp-bulk-install.txt new file mode 100644 index 0000000000..0edb7d75ad --- /dev/null +++ b/deps-lock/.tmp-bulk-install.txt @@ -0,0 +1,2 @@ +setuptools==75.1.0 +wheel==0.44.0 diff --git a/deps-lock/.tmp-full-remaining-install.txt b/deps-lock/.tmp-full-remaining-install.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/deps-lock/.tmp-full-remaining-skipped.txt b/deps-lock/.tmp-full-remaining-skipped.txt new file mode 100644 index 0000000000..4ab8385f4f --- /dev/null +++ b/deps-lock/.tmp-full-remaining-skipped.txt @@ -0,0 +1,36 @@ +anaconda-anon-usage @ file:///C:/b/abs_e8r_zga7xy/croot/anaconda-anon-usage_1732732454901/work +archspec @ file:///croot/archspec_1709217642129/work +boltons @ file:///C:/b/abs_707eo7c09t/croot/boltons_1677628723117/work +Brotli @ file:///C:/b/abs_3d36mno480/croot/brotli-split_1714483178642/work +cffi @ file:///C:/b/abs_90yq4lmu83/croot/cffi_1726856448345/work +colorama @ file:///C:/b/abs_a9ozq0l032/croot/colorama_1672387194846/work +conda @ file:///C:/b/abs_3bs4tei4e9/croot/conda_1733841834375/work +conda-anaconda-telemetry @ file:///C:/b/abs_b5wbfhyt0i/croot/conda-anaconda-telemetry_1733260551861/work +conda-content-trust @ file:///C:/b/abs_bdfatn_wzf/croot/conda-content-trust_1714483201909/work +conda-libmamba-solver @ file:///croot/conda-libmamba-solver_1727775630457/work/src +conda-package-handling @ file:///C:/b/abs_7fz3aferfv/croot/conda-package-handling_1731369038903/work +conda_package_streaming @ file:///C:/b/abs_bdz9vbvbh2/croot/conda-package-streaming_1731366449946/work +cryptography @ file:///C:/b/abs_e2lzchf4i6/croot/cryptography_1732130411942/work +distro @ file:///C:/b/abs_71xr36ua5r/croot/distro_1714488282676/work +frozendict @ file:///C:/b/abs_2alamqss6p/croot/frozendict_1713194885124/work +jsonpatch @ file:///C:/b/abs_4fdm88t7zi/croot/jsonpatch_1714483974578/work +libmambapy @ file:///C:/b/abs_7fjjcok9fe/croot/mamba-split_1732896315069/work/libmambapy +matplotlib==3.9.2 +menuinst @ file:///C:/b/abs_cabvzz4p7a/croot/menuinst_1731364936347/work +numpy==1.26.4 +platformdirs @ file:///C:/b/abs_b6z_yqw_ii/croot/platformdirs_1692205479426/work +pluggy @ file:///C:/b/abs_dfec_m79vo/croot/pluggy_1733170145382/work +protobuf==4.25.3 +pycolmap @ git+https://github.com/rmbrualla/pycolmap.git@cc7ea4b7301720ac29287dbe450952511b32125e +pycosat @ file:///C:/b/abs_5csdern___/croot/pycosat_1714513102923/work +pycparser @ file:///tmp/build/80754af9/pycparser_1636541352034/work +PySocks @ file:///C:/ci_310/pysocks_1642089375450/work +ruamel.yaml @ file:///C:/b/abs_0cunwx_ww6/croot/ruamel.yaml_1727980181547/work +ruamel.yaml.clib @ file:///C:/b/abs_5fk8zi6n09/croot/ruamel.yaml.clib_1727769837359/work +tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@6ee3546bda615f51abe684ce9edefeb414689135#subdirectory=bindings/torch +torch==2.1.2+cu118 +torchvision==0.16.2+cu118 +tqdm @ file:///C:/b/abs_77wju137gk/croot/tqdm_1724853945787/work +truststore @ file:///C:/b/abs_55z7b3r045/croot/truststore_1695245455435/work +win-inet-pton @ file:///C:/ci_310/win_inet_pton_1642658466512/work +zstandard @ file:///C:/b/abs_31t8xmrv_h/croot/zstandard_1731356578015/work diff --git a/deps-lock/bootstrap-env.txt b/deps-lock/bootstrap-env.txt new file mode 100644 index 0000000000..2c4cdc0e4f --- /dev/null +++ b/deps-lock/bootstrap-env.txt @@ -0,0 +1,22 @@ +NS_SELECTED_MSVC_TOOLSET=14.38.33130 +NS_SELECTED_MSVC_CL=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\bin\Hostx64\x64\cl.exe +CC=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\bin\Hostx64\x64\cl.exe +CXX=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\bin\Hostx64\x64\cl.exe +CUDAHOSTCXX=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\bin\Hostx64\x64\cl.exe +CMAKE_CUDA_HOST_COMPILER=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\bin\Hostx64\x64\cl.exe +CMAKE_GENERATOR=Visual Studio 17 2022 +CMAKE_GENERATOR_TOOLSET=v143,version=14.38.33130 +CUDA_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8 +CUDA_HOME=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8 +CUDAToolkit_ROOT=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8 +WindowsSdkDir=C:\Program Files (x86)\Windows Kits\10 +WindowsSDKVersion=10.0.26100.0 +UniversalCRTSdkDir=C:\Program Files (x86)\Windows Kits\10 +UCRTVersion=10.0.26100.0 +VCToolsInstallDir=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130 +VCINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC +VSINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools +INCLUDE=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\include;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\VS\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\winrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\cppwinrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um +LIB=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\lib\x64;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x64;C:\Program Files (x86)\Windows Kits\10\lib\10.0.26100.0\ucrt\x64;C:\Program Files (x86)\Windows Kits\10\lib\10.0.26100.0\um\x64 +LIBPATH=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\lib\x64;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\lib\x86\store\references;C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.26100.0;C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0;C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319 +PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\bin;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\libnvvp;C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable\Scripts;C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable;C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable\Library\bin;C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable\Library\usr\bin;C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable\bin;C:\Users\crist\Documents\nerfstudio_custom\.conda\envs\nerfstudio-portable;C:\Program Files\Git\cmd;C:\Program Files\Git\bin;C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable\Library\mingw-w64\bin;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\bin\HostX64\x64;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\IDE\VC\VCPackages;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\IDE\CommonExtensions\Microsoft\TestWindow;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\bin\Roslyn;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Team Tools\DiagnosticsHub\Collector;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\IDE\Extensions\Microsoft\CodeCoverage.Console;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\Llvm\x64\bin;C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64;C:\Program Files (x86)\Windows Kits\10\bin\x64;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\MSBuild\Current\Bin\amd64;C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\IDE;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\Tools;C:\Users\crist\Documenti\nerfstudio_custom\.conda\condabin;C:\Program Files\Microsoft MPI\Bin;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0;C:\WINDOWS\System32\OpenSSH;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\Microsoft SQL Server\150\Tools\Binn;C:\Program Files\Microsoft SQL Server\130\Tools\Binn;C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn;C:\Program Files\dotnet;C:\Program Files\GitHub CLI;C:\Program Files\NVIDIA Corporation\NVIDIA App\NvDLISR;C:\ProgramData\NVIDIA Corporation\OptiX SDK 9.0.0;C:\Program Files\NVIDIA Corporation\Nsight Compute 2025.1.0;C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64.;C:\Program Files\Docker\Docker\resources\bin;C:\Program Files (x86)\GtkSharp\2.12\bin;C:\FrankBuildTools\CMake\bin;C:\Program Files (x86)\Intel\oneAPI\mkl\latest\redist\intel64;C:\Users\crist\.julia\juliaup\julia-1.12.3+0.x64.w64.mingw32\bin;C:\FrankBuildTools\nodejs;C:\ProgramData\chocolatey\bin;C:\vcpkg;C:\Program Files (x86)\Windows Kits\10\Windows Performance Toolkit;C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x64;C:\FrankLibBuilds\colmap\build\vcpkg_installed\x64-windows\tools\Qt6\bin;C:\FrankBuildTools\VulkanSDK\1.4.335.0\Bin;C:\vcpkg\installed\x64-windows\tools\bazel.exe;C:\Program Files\Git LFS;C:\Users\crist\AppData\Local\Programs\Python\Python312\Scripts;C:\Users\crist\AppData\Local\Programs\Python\Python312;C:\Users\crist\AppData\Local\Programs\Python\Python314\Scripts;C:\Users\crist\AppData\Local\Programs\Python\Python314;C:\Users\crist\.cargo\bin;C:\Users\crist\AppData\Local\Microsoft\WindowsApps;C:\Users\crist\AppData\Local\Programs\Microsoft VS Code\bin;C:\Users\crist\.dotnet\tools;C:\Users\crist\AppData\Local\GitHubDesktop\bin;C:\Users\crist\Documents\ffmpeg\bin.;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8\lib\x64;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.8\lib\x64;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.8\include;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.8;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4\lib\x64;C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.4;C:\Users\crist\AppData\Local\Programs\Ollama;C:\FrankBuildTools\swigwin-4.4.0\CCache;C:\FrankLibBuilds\colmap\build\src\colmap\exe\Release;C:\FrankBuildTools\Java\bin;E:\UnityEditor\6000.3.1f1\Editor;C:\FrankBuildTools\NSIS\NSIS.exe;C:\Users\crist\AppData\Roaming\npm;C:\Users\crist\AppData\Local\Microsoft\WinGet\Packages\Bazel.Bazelisk_Microsoft.Winget.Source_8wekyb3d8bbwe;.;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\Common7\IDE\VC\Linux\bin\ConnectionManagerExe;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\vcpkg diff --git a/deps-lock/build-plan.json b/deps-lock/build-plan.json new file mode 100644 index 0000000000..15180d5026 --- /dev/null +++ b/deps-lock/build-plan.json @@ -0,0 +1,165 @@ +{ + "numpy_stable": "numpy==1.26.4", + "torch_preinstall": [ + "torch==2.1.2+cu118", + "torchvision==0.16.2+cu118" + ], + "torch_index": "https://download.pytorch.org/whl/cu118", + "pyg_wheels": [], + "pyg_index_template": "https://data.pyg.org/whl/{torch_tag}.html", + "tinycudann": { + "requirement": "tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@6ee3546bda615f51abe684ce9edefeb414689135#subdirectory=bindings/torch", + "cuda_arch": "86" + }, + "pycolmap": { + "requirement": "git+https://github.com/rmbrualla/pycolmap.git" + }, + "deferred": [ + "tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@6ee3546bda615f51abe684ce9edefeb414689135#subdirectory=bindings/torch" + ], + "nerfstudio_methods_protected": { + "feature-splatting": { + "pip_names": [ + "feature-splatting", + "feature_splatting" + ], + "install_ref": "git+https://github.com/vuer-ai/feature-splatting", + "patch_rel": "feature-splatting", + "category": "method" + }, + "igs2gs": { + "pip_names": [ + "igs2gs" + ], + "install_ref": "git+https://github.com/cvachha/instruct-gs2gs", + "patch_rel": "igs2gs", + "category": "method" + }, + "lerf": { + "pip_names": [ + "lerf" + ], + "install_ref": "git+https://github.com/kerrj/lerf", + "patch_rel": "lerf", + "category": "method" + }, + "livescene": { + "pip_names": [ + "livescene" + ], + "install_ref": "git+https://github.com/Tavish9/livescene", + "patch_rel": "livescene", + "category": "method" + }, + "nerfplayer": { + "pip_names": [ + "nerfplayer" + ], + "install_ref": "git+https://github.com/lsongx/nerfplayer-nerfstudio.git", + "patch_rel": "nerfplayer", + "category": "method" + }, + "opennerf": { + "pip_names": [ + "opennerf" + ], + "install_ref": "git+https://github.com/opennerf/opennerf", + "patch_rel": "opennerf", + "category": "method" + }, + "pynerf": { + "pip_names": [ + "pynerf" + ], + "install_ref": "git+https://github.com/hturki/pynerf", + "patch_rel": "pynerf", + "category": "method" + }, + "splatfacto-w": { + "pip_names": [ + "splatfacto-w", + "splatfactow" + ], + "install_ref": "git+https://github.com/KevinXu02/splatfacto-w", + "patch_rel": "splatfacto-w", + "category": "method" + }, + "tetra-nerf": { + "pip_names": [ + "tetra-nerf", + "tetra_nerf" + ], + "install_ref": "git+https://github.com/jkulhanek/tetra-nerf", + "patch_rel": "tetra-nerf", + "category": "method" + }, + "zipnerf-pytorch": { + "pip_names": [ + "zipnerf", + "zipnerf-pytorch" + ], + "install_ref": "git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git", + "patch_rel": "zipnerf-pytorch", + "category": "method" + } + }, + "nerfstudio_core_overrides": { + "pycolmap": { + "pip_names": [ + "pycolmap" + ], + "install_ref": "git+https://github.com/rmbrualla/pycolmap.git", + "patch_rel": null, + "category": "core_dependency", + "enforce_as_standard": true + } + }, + "skipped_from_bulk": [ + "anaconda-anon-usage @ file:///C:/b/abs_e8r_zga7xy/croot/anaconda-anon-usage_1732732454901/work", + "archspec @ file:///croot/archspec_1709217642129/work", + "boltons @ file:///C:/b/abs_707eo7c09t/croot/boltons_1677628723117/work", + "Brotli @ file:///C:/b/abs_3d36mno480/croot/brotli-split_1714483178642/work", + "cffi @ file:///C:/b/abs_90yq4lmu83/croot/cffi_1726856448345/work", + "colorama @ file:///C:/b/abs_a9ozq0l032/croot/colorama_1672387194846/work", + "conda @ file:///C:/b/abs_3bs4tei4e9/croot/conda_1733841834375/work", + "conda-anaconda-telemetry @ file:///C:/b/abs_b5wbfhyt0i/croot/conda-anaconda-telemetry_1733260551861/work", + "conda-content-trust @ file:///C:/b/abs_bdfatn_wzf/croot/conda-content-trust_1714483201909/work", + "conda-libmamba-solver @ file:///croot/conda-libmamba-solver_1727775630457/work/src", + "conda-package-handling @ file:///C:/b/abs_7fz3aferfv/croot/conda-package-handling_1731369038903/work", + "conda_package_streaming @ file:///C:/b/abs_bdz9vbvbh2/croot/conda-package-streaming_1731366449946/work", + "cryptography @ file:///C:/b/abs_e2lzchf4i6/croot/cryptography_1732130411942/work", + "distro @ file:///C:/b/abs_71xr36ua5r/croot/distro_1714488282676/work", + "frozendict @ file:///C:/b/abs_2alamqss6p/croot/frozendict_1713194885124/work", + "jsonpatch @ file:///C:/b/abs_4fdm88t7zi/croot/jsonpatch_1714483974578/work", + "libmambapy @ file:///C:/b/abs_7fjjcok9fe/croot/mamba-split_1732896315069/work/libmambapy", + "menuinst @ file:///C:/b/abs_cabvzz4p7a/croot/menuinst_1731364936347/work", + "numpy==1.26.4", + "platformdirs @ file:///C:/b/abs_b6z_yqw_ii/croot/platformdirs_1692205479426/work", + "pluggy @ file:///C:/b/abs_dfec_m79vo/croot/pluggy_1733170145382/work", + "pycolmap @ git+https://github.com/rmbrualla/pycolmap.git@cc7ea4b7301720ac29287dbe450952511b32125e", + "pycosat @ file:///C:/b/abs_5csdern___/croot/pycosat_1714513102923/work", + "pycparser @ file:///tmp/build/80754af9/pycparser_1636541352034/work", + "PySocks @ file:///C:/ci_310/pysocks_1642089375450/work", + "ruamel.yaml @ file:///C:/b/abs_0cunwx_ww6/croot/ruamel.yaml_1727980181547/work", + "ruamel.yaml.clib @ file:///C:/b/abs_5fk8zi6n09/croot/ruamel.yaml.clib_1727769837359/work", + "torch==2.1.2+cu118", + "torchvision==0.16.2+cu118", + "tqdm @ file:///C:/b/abs_77wju137gk/croot/tqdm_1724853945787/work", + "truststore @ file:///C:/b/abs_55z7b3r045/croot/truststore_1695245455435/work", + "win-inet-pton @ file:///C:/ci_310/win_inet_pton_1642658466512/work", + "zstandard @ file:///C:/b/abs_31t8xmrv_h/croot/zstandard_1731356578015/work" + ], + "build_tooling": [ + "pip", + "setuptools", + "wheel", + "Cython", + "pkgconfig", + "pybind11" + ], + "preferred_msvc": "14.38", + "bootstrap_mode": "subprocess-shell-bootstrap", + "selected_toolset": "14.38.33130", + "selected_installation": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools", + "cuda_root": "C:\\PROGRA~1\\NVIDIA~2\\CUDA\\v11.8" +} diff --git a/deps-lock/conda-explicit-win-64.txt b/deps-lock/conda-explicit-win-64.txt new file mode 100644 index 0000000000..5fe77ed537 --- /dev/null +++ b/deps-lock/conda-explicit-win-64.txt @@ -0,0 +1,86 @@ +# This file may be used to create an environment using: +# $ conda create --name --file +# platform: win-64 +# created-by: conda 24.11.1 +@EXPLICIT +https://repo.anaconda.com/pkgs/main/win-64/blas-1.0-mkl.conda#29c8be9152b7cbf29578794154d2408f +https://repo.anaconda.com/pkgs/main/win-64/ca-certificates-2026.3.19-haa95532_0.conda#646f2cc64c282566396335d4e352a3b4 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-cccl-11.8.89-0.tar.bz2#06310fc13c30726aae25014bf2432983 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-cudart-11.8.89-0.tar.bz2#cd0f6ab42e0ccba5f6899c531ea193c1 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-cuobjdump-11.8.86-0.tar.bz2#af69c3384c9a61a1e5eac9c2d8eea173 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-cupti-11.8.87-0.tar.bz2#f18f6268a222d476c804d4adadd4926a +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-cuxxfilt-11.8.86-0.tar.bz2#31604ed72267dc92db7e4bfc626a6d48 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-documentation-11.8.86-0.tar.bz2#6764b29aaf043a0d10a6eae0b0afa1e0 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-memcheck-11.8.86-0.tar.bz2#af2ac23440715e346977009696c60c5e +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-nvcc-11.8.89-0.tar.bz2#beb07e3da086266e316592eda018ac97 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-nvdisasm-11.8.86-0.tar.bz2#02a03184b806e4595fb329044a307a0e +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-nvml-dev-11.8.86-0.tar.bz2#0e12b0d7d14a9865878d679848cafb13 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-nvprof-11.8.87-0.tar.bz2#5196933abb58ef386b67f74121762645 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-nvprune-11.8.86-0.tar.bz2#7e711308e414ac46246819b548e143de +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-nvrtc-11.8.89-0.tar.bz2#d692bd090a4a9638ac15709cde2400da +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-nvtx-11.8.86-0.tar.bz2#7874207353c834d34217555785859dba +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-profiler-api-11.8.86-0.tar.bz2#6fadbcf3755f1bacba3ad640eda20f87 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-sanitizer-api-11.8.86-0.tar.bz2#85522c1d93ab470900f076f6c2315d8e +https://repo.anaconda.com/pkgs/main/win-64/icc_rt-2022.1.0-h6049295_2.conda#4ea9e3682a5114c1ee3dc09bac898e8d +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libcublas-11.11.3.6-0.tar.bz2#750e01875ed59059ae043d09d262968d +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libcufft-10.9.0.58-0.tar.bz2#df178db30b5abcaa0a5f3a369a1fe19c +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libcurand-10.3.0.86-0.tar.bz2#82439a8d24b44a6f355e3192200b4210 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libcusolver-11.4.1.48-0.tar.bz2#43cd3c2bcbdfac91708e96fe6b554676 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libcusparse-11.7.5.86-0.tar.bz2#b2cbca2503fdb48486228f97265fc4dd +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libnpp-11.8.0.86-0.tar.bz2#84696e7fac0af2c9fe57eec5e2ca56f5 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libnvjpeg-11.9.0.86-0.tar.bz2#9ddfe10567159ae9380d4b10d8cf1670 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/nsight-compute-2022.3.0.22-0.tar.bz2#f1fbc010757d444b4147607d2d953c4f +https://repo.anaconda.com/pkgs/main/noarch/tzdata-2025a-h04d1e81_0.conda#885caf42f821b98b3321dc4108511a3d +https://repo.anaconda.com/pkgs/main/win-64/ucrt-10.0.22621.0-haa95532_0.conda#15e1b10231d7d236520501fcfb440f31 +https://repo.anaconda.com/pkgs/main/win-64/vs2015_runtime-14.42.34433-he0abc0d_4.conda#ac6b66049b87b660a89d58c35c620801 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-command-line-tools-11.8.0-0.tar.bz2#48ff9d443263f4b0dacf646678b8da62 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-compiler-11.8.0-0.tar.bz2#c69b86bf9e15f49eb3707308121afa54 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-cudart-dev-11.8.89-0.tar.bz2#a4b0b3a1b7aa79ff39f6d3b1e7c62de3 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-libraries-11.8.0-0.tar.bz2#4a0d16015f1480c6b6845a4d17b9563b +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-nsight-compute-11.8.0-0.tar.bz2#ab44f1dc4d4a6ad7e32861e2996aa85d +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-nvrtc-dev-11.8.89-0.tar.bz2#18132d5744a60ec64ab62e35a7a4d618 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-nvvp-11.8.87-0.tar.bz2#4eaf62e120017b9c7f145bbdff22587e +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libcublas-dev-11.11.3.6-0.tar.bz2#ec868c016e21a206980c57cacc2d8fbc +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libcufft-dev-10.9.0.58-0.tar.bz2#3324bab83e7415785abdcc80ebceda72 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libcurand-dev-10.3.0.86-0.tar.bz2#bdef6a4daecc54a42ad221a5d5a2f129 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libcusolver-dev-11.4.1.48-0.tar.bz2#5be85962afcb4326fc6e80294d2b15e5 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libcusparse-dev-11.7.5.86-0.tar.bz2#e2fe98ab4b1442f85024c2fe96bc7a61 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libnpp-dev-11.8.0.86-0.tar.bz2#b7a4f974dec24d055e46217db1b263a6 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/libnvjpeg-dev-11.9.0.86-0.tar.bz2#f116753a5673e7b113f5e06081059f6d +https://conda.anaconda.org/conda-forge/win-64/libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_10.conda#8a86073cf3b343b87d03f41790d8b4e5 +https://repo.anaconda.com/pkgs/main/win-64/vc-14.42-haa95532_4.conda#3a087fe8b4809313b355b19c782fb502 +https://repo.anaconda.com/pkgs/main/win-64/bzip2-1.0.8-h2bbff1b_6.conda#33e784123d565c38e68945f07b461282 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-libraries-dev-11.8.0-0.tar.bz2#4dceddb905013e47bee99757d42dfdd4 +https://repo.anaconda.com/pkgs/main/win-64/double-conversion-3.3.1-h5da7b33_0.conda#e03a36e0b58806431791a07c144a7a28 +https://repo.anaconda.com/pkgs/main/win-64/intel-openmp-2023.1.0-h59b6b97_46320.conda#24ec0112499542d8170daa38552134d9 +https://repo.anaconda.com/pkgs/main/win-64/libffi-3.4.4-hd77b12b_1.conda#9807b377e11739ae3e920e10e607e460 +https://conda.anaconda.org/conda-forge/win-64/libgomp-15.2.0-h8ee18e1_18.conda#939fb173e2a4d4e980ef689e99b35223 +https://repo.anaconda.com/pkgs/main/win-64/libuv-1.48.0-h827c3e9_0.conda#56f8d1b797f663630b850da6ca0f8b8a +https://repo.anaconda.com/pkgs/main/win-64/lz4-c-1.9.4-h2bbff1b_1.conda#723e3ccd4ef7c58ddbfeebe69abff662 +https://repo.anaconda.com/pkgs/main/win-64/openssl-3.0.16-h3f729d1_0.conda#5ceb57e424ffe9918ba8f8af4fcc936a +https://repo.anaconda.com/pkgs/main/win-64/sqlite-3.45.3-h2bbff1b_0.conda#c5b3b929349655302bf811c45571da6d +https://repo.anaconda.com/pkgs/main/win-64/tbb-2021.8.0-h59b6b97_0.conda#aa60f11c1789a50a20be2e657e31513a +https://repo.anaconda.com/pkgs/main/win-64/xz-5.6.4-h4754444_1.conda#6036999a3a2c7a3e3739d6b9351fcb0b +https://repo.anaconda.com/pkgs/main/win-64/zlib-1.2.13-h8cc25b3_1.conda#1f7ea85632611b25599e4cddf5b51d7d +https://conda.anaconda.org/conda-forge/win-64/_openmp_mutex-4.5-20_gnu.conda#1626967b574d1784b578b52eaeb071e7 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-visual-tools-11.8.0-0.tar.bz2#bd42a83366c30783c005a5905df7f282 +https://repo.anaconda.com/pkgs/main/win-64/mkl-2023.1.0-h6b88ed4_46358.conda#15d96e057d3e7150f5504ead12036788 +https://repo.anaconda.com/pkgs/main/win-64/tk-8.6.14-h0416ee5_0.conda#da75707c571825eb2ad0eb806710b16b +https://repo.anaconda.com/pkgs/main/win-64/zstd-1.5.6-h8880b57_0.conda#0ca0f609c72a6ae9a27985be56b6c351 +https://repo.anaconda.com/pkgs/main/win-64/cmake-3.31.2-h53b1909_0.conda#20f5b9814d55c77418b596035be4e756 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-tools-11.8.0-0.tar.bz2#a3114065848819d5ccc9c802c725a734 +https://conda.anaconda.org/conda-forge/win-64/libgcc-15.2.0-h8ee18e1_18.conda#b085746891cca3bd2704a450a7b4b5ce +https://repo.anaconda.com/pkgs/main/win-64/python-3.10.16-h4607a30_1.conda#c5416839497a1f2ff6a6d5bc911a97c4 +https://conda.anaconda.org/nvidia/label/cuda-11.8.0/win-64/cuda-toolkit-11.8.0-0.tar.bz2#a2740a0d2bdc9221789f3016a866ae32 +https://conda.anaconda.org/conda-forge/win-64/gmp-6.3.0-hfeafd45_2.conda#74558de25a206a7dff062fd4f5ff2d8b +https://repo.anaconda.com/pkgs/main/win-64/mkl-service-2.4.0-py310h827c3e9_2.conda#1767bb309d640a980f9a4482e607c035 +https://repo.anaconda.com/pkgs/main/noarch/pip-26.0.1-pyhc872135_0.conda#5835195770c796fcd0a15547e58b90f9 +https://repo.anaconda.com/pkgs/main/win-64/numpy-base-1.26.4-py310h65a83cf_0.conda#d4a5a5234ae24d1aa76ef6cf432ca14c +https://repo.anaconda.com/pkgs/main/noarch/opt_einsum-3.3.0-pyhd3eb1b0_1.conda#53205b8b5762c06f85b6bb7abd4f496e +https://repo.anaconda.com/pkgs/main/win-64/mkl_fft-1.3.11-py310h827c3e9_0.conda#5497dc96f785184d402057751207f735 +https://repo.anaconda.com/pkgs/main/win-64/mkl_random-1.2.8-py310hc64d2fc_0.conda#3bdc6f7a5e1df9edcbba28a5eacfac3e +https://repo.anaconda.com/pkgs/main/win-64/numpy-1.26.4-py310h055cbcc_0.conda#8ac27b22c049bb89df62c5401b387d96 +https://repo.anaconda.com/pkgs/main/win-64/ml_dtypes-0.5.1-py310h094160a_0.conda#fca0e8d5e51e888db7a06b19ee9acd8d +https://repo.anaconda.com/pkgs/main/win-64/scipy-1.15.3-py310h180bac5_0.conda#60784c706891cb8a9befbaf4f3852685 +https://repo.anaconda.com/pkgs/main/win-64/jaxlib-0.4.35-cpu_py310h4446c90_2.conda#9a1e0c67eef4661aafa0a784304c0a27 +https://repo.anaconda.com/pkgs/main/win-64/jax-0.4.35-py310haa95532_0.conda#faa906e9a07524ee2fff568066b45abc diff --git a/deps-lock/conda-list.json b/deps-lock/conda-list.json new file mode 100644 index 0000000000..4e165ebd36 --- /dev/null +++ b/deps-lock/conda-list.json @@ -0,0 +1,4662 @@ +[ + { + "base_url": "https://conda.anaconda.org/conda-forge", + "build_number": 20, + "build_string": "20_gnu", + "channel": "conda-forge", + "dist_name": "_openmp_mutex-4.5-20_gnu", + "name": "_openmp_mutex", + "platform": "win-64", + "version": "4.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "absl-py-2.2.2-pypi_0", + "name": "absl-py", + "platform": "pypi", + "version": "2.2.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "accelerate-0.19.0-pypi_0", + "name": "accelerate", + "platform": "pypi", + "version": "0.19.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "affine-2.4.0-pypi_0", + "name": "affine", + "platform": "pypi", + "version": "2.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "aiohappyeyeballs-2.6.1-pypi_0", + "name": "aiohappyeyeballs", + "platform": "pypi", + "version": "2.6.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "aiohttp-3.13.5-pypi_0", + "name": "aiohttp", + "platform": "pypi", + "version": "3.13.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "aiosignal-1.4.0-pypi_0", + "name": "aiosignal", + "platform": "pypi", + "version": "1.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "alabaster-1.0.0-pypi_0", + "name": "alabaster", + "platform": "pypi", + "version": "1.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "annotated-doc-0.0.4-pypi_0", + "name": "annotated-doc", + "platform": "pypi", + "version": "0.0.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "annotated-types-0.7.0-pypi_0", + "name": "annotated-types", + "platform": "pypi", + "version": "0.7.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "antlr4-python3-runtime-4.9.3-pypi_0", + "name": "antlr4-python3-runtime", + "platform": "pypi", + "version": "4.9.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "anyio-4.9.0-pypi_0", + "name": "anyio", + "platform": "pypi", + "version": "4.9.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "appdirs-1.4.4-pypi_0", + "name": "appdirs", + "platform": "pypi", + "version": "1.4.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "argon2-cffi-23.1.0-pypi_0", + "name": "argon2-cffi", + "platform": "pypi", + "version": "23.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "argon2-cffi-bindings-21.2.0-pypi_0", + "name": "argon2-cffi-bindings", + "platform": "pypi", + "version": "21.2.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "arrow-1.3.0-pypi_0", + "name": "arrow", + "platform": "pypi", + "version": "1.3.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "asttokens-3.0.0-pypi_0", + "name": "asttokens", + "platform": "pypi", + "version": "3.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "astunparse-1.6.3-pypi_0", + "name": "astunparse", + "platform": "pypi", + "version": "1.6.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "async-lru-2.0.5-pypi_0", + "name": "async-lru", + "platform": "pypi", + "version": "2.0.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "async-timeout-5.0.1-pypi_0", + "name": "async-timeout", + "platform": "pypi", + "version": "5.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "atomicwrites-1.4.0-pypi_0", + "name": "atomicwrites", + "platform": "pypi", + "version": "1.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "attrs-25.3.0-pypi_0", + "name": "attrs", + "platform": "pypi", + "version": "25.3.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "av-17.0.0-pypi_0", + "name": "av", + "platform": "pypi", + "version": "17.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "awscli-1.33.18-pypi_0", + "name": "awscli", + "platform": "pypi", + "version": "1.33.18" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "babel-2.17.0-pypi_0", + "name": "babel", + "platform": "pypi", + "version": "2.17.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "beautifulsoup4-4.13.3-pypi_0", + "name": "beautifulsoup4", + "platform": "pypi", + "version": "4.13.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "bidict-0.23.1-pypi_0", + "name": "bidict", + "platform": "pypi", + "version": "0.23.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "bitsandbytes-0.43.0-pypi_0", + "name": "bitsandbytes", + "platform": "pypi", + "version": "0.43.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "black-26.3.1-pypi_0", + "name": "black", + "platform": "pypi", + "version": "26.3.1" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 1, + "build_string": "mkl", + "channel": "pkgs/main", + "dist_name": "blas-1.0-mkl", + "name": "blas", + "platform": "win-64", + "version": "1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "bleach-6.2.0-pypi_0", + "name": "bleach", + "platform": "pypi", + "version": "6.2.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "blinker-1.9.0-pypi_0", + "name": "blinker", + "platform": "pypi", + "version": "1.9.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "botocore-1.34.136-pypi_0", + "name": "botocore", + "platform": "pypi", + "version": "1.34.136" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 6, + "build_string": "h2bbff1b_6", + "channel": "pkgs/main", + "dist_name": "bzip2-1.0.8-h2bbff1b_6", + "name": "bzip2", + "platform": "win-64", + "version": "1.0.8" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "haa95532_0", + "channel": "pkgs/main", + "dist_name": "ca-certificates-2026.3.19-haa95532_0", + "name": "ca-certificates", + "platform": "win-64", + "version": "2026.3.19" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "cachetools-5.5.2-pypi_0", + "name": "cachetools", + "platform": "pypi", + "version": "5.5.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "certifi-2026.2.25-pypi_0", + "name": "certifi", + "platform": "pypi", + "version": "2026.2.25" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "cffi-1.17.1-pypi_0", + "name": "cffi", + "platform": "pypi", + "version": "1.17.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "cfgv-3.5.0-pypi_0", + "name": "cfgv", + "platform": "pypi", + "version": "3.5.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "cgal-6.0.1.post202410241521-pypi_0", + "name": "cgal", + "platform": "pypi", + "version": "6.0.1.post202410241521" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "charset-normalizer-2.1.1-pypi_0", + "name": "charset-normalizer", + "platform": "pypi", + "version": "2.1.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "click-8.3.2-pypi_0", + "name": "click", + "platform": "pypi", + "version": "8.3.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "click-plugins-1.1.1.2-pypi_0", + "name": "click-plugins", + "platform": "pypi", + "version": "1.1.1.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "cligj-0.7.2-pypi_0", + "name": "cligj", + "platform": "pypi", + "version": "0.7.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "clip-1.0-pypi_0", + "name": "clip", + "platform": "pypi", + "version": "1.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "h53b1909_0", + "channel": "pkgs/main", + "dist_name": "cmake-3.31.2-h53b1909_0", + "name": "cmake", + "platform": "win-64", + "version": "3.31.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "colorama-0.4.6-pypi_0", + "name": "colorama", + "platform": "pypi", + "version": "0.4.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "coloredlogs-15.0.1-pypi_0", + "name": "coloredlogs", + "platform": "pypi", + "version": "15.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "colorlog-6.9.0-pypi_0", + "name": "colorlog", + "platform": "pypi", + "version": "6.9.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "comet-ml-3.49.7-pypi_0", + "name": "comet-ml", + "platform": "pypi", + "version": "3.49.7" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "comm-0.2.2-pypi_0", + "name": "comm", + "platform": "pypi", + "version": "0.2.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "configargparse-1.7-pypi_0", + "name": "configargparse", + "platform": "pypi", + "version": "1.7" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "configobj-5.0.9-pypi_0", + "name": "configobj", + "platform": "pypi", + "version": "5.0.9" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "contourpy-1.3.1-pypi_0", + "name": "contourpy", + "platform": "pypi", + "version": "1.3.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "cryptography-44.0.2-pypi_0", + "name": "cryptography", + "platform": "pypi", + "version": "44.0.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "cuda-backend-0.0.0-pypi_0", + "name": "cuda-backend", + "platform": "pypi", + "version": "0.0.0" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-cccl-11.8.89-0", + "name": "cuda-cccl", + "platform": "win-64", + "version": "11.8.89" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-command-line-tools-11.8.0-0", + "name": "cuda-command-line-tools", + "platform": "win-64", + "version": "11.8.0" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-compiler-11.8.0-0", + "name": "cuda-compiler", + "platform": "win-64", + "version": "11.8.0" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-cudart-11.8.89-0", + "name": "cuda-cudart", + "platform": "win-64", + "version": "11.8.89" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-cudart-dev-11.8.89-0", + "name": "cuda-cudart-dev", + "platform": "win-64", + "version": "11.8.89" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-cuobjdump-11.8.86-0", + "name": "cuda-cuobjdump", + "platform": "win-64", + "version": "11.8.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-cupti-11.8.87-0", + "name": "cuda-cupti", + "platform": "win-64", + "version": "11.8.87" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-cuxxfilt-11.8.86-0", + "name": "cuda-cuxxfilt", + "platform": "win-64", + "version": "11.8.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-documentation-11.8.86-0", + "name": "cuda-documentation", + "platform": "win-64", + "version": "11.8.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-libraries-11.8.0-0", + "name": "cuda-libraries", + "platform": "win-64", + "version": "11.8.0" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-libraries-dev-11.8.0-0", + "name": "cuda-libraries-dev", + "platform": "win-64", + "version": "11.8.0" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-memcheck-11.8.86-0", + "name": "cuda-memcheck", + "platform": "win-64", + "version": "11.8.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-nsight-compute-11.8.0-0", + "name": "cuda-nsight-compute", + "platform": "win-64", + "version": "11.8.0" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-nvcc-11.8.89-0", + "name": "cuda-nvcc", + "platform": "win-64", + "version": "11.8.89" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-nvdisasm-11.8.86-0", + "name": "cuda-nvdisasm", + "platform": "win-64", + "version": "11.8.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-nvml-dev-11.8.86-0", + "name": "cuda-nvml-dev", + "platform": "win-64", + "version": "11.8.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-nvprof-11.8.87-0", + "name": "cuda-nvprof", + "platform": "win-64", + "version": "11.8.87" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-nvprune-11.8.86-0", + "name": "cuda-nvprune", + "platform": "win-64", + "version": "11.8.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-nvrtc-11.8.89-0", + "name": "cuda-nvrtc", + "platform": "win-64", + "version": "11.8.89" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-nvrtc-dev-11.8.89-0", + "name": "cuda-nvrtc-dev", + "platform": "win-64", + "version": "11.8.89" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-nvtx-11.8.86-0", + "name": "cuda-nvtx", + "platform": "win-64", + "version": "11.8.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-nvvp-11.8.87-0", + "name": "cuda-nvvp", + "platform": "win-64", + "version": "11.8.87" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-profiler-api-11.8.86-0", + "name": "cuda-profiler-api", + "platform": "win-64", + "version": "11.8.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-sanitizer-api-11.8.86-0", + "name": "cuda-sanitizer-api", + "platform": "win-64", + "version": "11.8.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-toolkit-11.8.0-0", + "name": "cuda-toolkit", + "platform": "win-64", + "version": "11.8.0" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-tools-11.8.0-0", + "name": "cuda-tools", + "platform": "win-64", + "version": "11.8.0" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "cuda-visual-tools-11.8.0-0", + "name": "cuda-visual-tools", + "platform": "win-64", + "version": "11.8.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "cycler-0.12.1-pypi_0", + "name": "cycler", + "platform": "pypi", + "version": "0.12.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "cython-3.2.4-pypi_0", + "name": "cython", + "platform": "pypi", + "version": "3.2.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "dash-3.0.2-pypi_0", + "name": "dash", + "platform": "pypi", + "version": "3.0.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "debugpy-1.8.14-pypi_0", + "name": "debugpy", + "platform": "pypi", + "version": "1.8.14" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "decorator-5.2.1-pypi_0", + "name": "decorator", + "platform": "pypi", + "version": "5.2.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "defusedxml-0.7.1-pypi_0", + "name": "defusedxml", + "platform": "pypi", + "version": "0.7.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "descartes-1.1.0-pypi_0", + "name": "descartes", + "platform": "pypi", + "version": "1.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "diffusers-0.16.1-pypi_0", + "name": "diffusers", + "platform": "pypi", + "version": "0.16.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "dill-0.3.9-pypi_0", + "name": "dill", + "platform": "pypi", + "version": "0.3.9" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "distlib-0.4.0-pypi_0", + "name": "distlib", + "platform": "pypi", + "version": "0.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "docker-pycreds-0.4.0-pypi_0", + "name": "docker-pycreds", + "platform": "pypi", + "version": "0.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "docstring-parser-0.16-pypi_0", + "name": "docstring-parser", + "platform": "pypi", + "version": "0.16" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "docutils-0.16-pypi_0", + "name": "docutils", + "platform": "pypi", + "version": "0.16" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "dotmap-1.3.30-pypi_0", + "name": "dotmap", + "platform": "pypi", + "version": "1.3.30" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "h5da7b33_0", + "channel": "pkgs/main", + "dist_name": "double-conversion-3.3.1-h5da7b33_0", + "name": "double-conversion", + "platform": "win-64", + "version": "3.3.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "dulwich-0.22.8-pypi_0", + "name": "dulwich", + "platform": "pypi", + "version": "0.22.8" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "einops-0.8.2-pypi_0", + "name": "einops", + "platform": "pypi", + "version": "0.8.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "everett-3.1.0-pypi_0", + "name": "everett", + "platform": "pypi", + "version": "3.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "exceptiongroup-1.2.2-pypi_0", + "name": "exceptiongroup", + "platform": "pypi", + "version": "1.2.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "execnet-2.1.2-pypi_0", + "name": "execnet", + "platform": "pypi", + "version": "2.1.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "executing-2.2.0-pypi_0", + "name": "executing", + "platform": "pypi", + "version": "2.2.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "fastjsonschema-2.21.1-pypi_0", + "name": "fastjsonschema", + "platform": "pypi", + "version": "2.21.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "feature-splatting-0.0.3-pypi_0", + "name": "feature-splatting", + "platform": "pypi", + "version": "0.0.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "filelock-3.25.2-pypi_0", + "name": "filelock", + "platform": "pypi", + "version": "3.25.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "fire-0.7.0-pypi_0", + "name": "fire", + "platform": "pypi", + "version": "0.7.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "flask-3.0.3-pypi_0", + "name": "flask", + "platform": "pypi", + "version": "3.0.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "flatbuffers-25.12.19-pypi_0", + "name": "flatbuffers", + "platform": "pypi", + "version": "25.12.19" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "fonttools-4.57.0-pypi_0", + "name": "fonttools", + "platform": "pypi", + "version": "4.57.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "fpsample-0.3.3-pypi_0", + "name": "fpsample", + "platform": "pypi", + "version": "0.3.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "fqdn-1.5.1-pypi_0", + "name": "fqdn", + "platform": "pypi", + "version": "1.5.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "freetype-py-2.5.1-pypi_0", + "name": "freetype-py", + "platform": "pypi", + "version": "2.5.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "frozenlist-1.8.0-pypi_0", + "name": "frozenlist", + "platform": "pypi", + "version": "1.8.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "fsspec-2026.2.0-pypi_0", + "name": "fsspec", + "platform": "pypi", + "version": "2026.2.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "ftfy-6.3.1-pypi_0", + "name": "ftfy", + "platform": "pypi", + "version": "6.3.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "gast-0.7.0-pypi_0", + "name": "gast", + "platform": "pypi", + "version": "0.7.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "gdown-5.2.0-pypi_0", + "name": "gdown", + "platform": "pypi", + "version": "5.2.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "gin-config-0.5.0-pypi_0", + "name": "gin-config", + "platform": "pypi", + "version": "0.5.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "gitdb-4.0.12-pypi_0", + "name": "gitdb", + "platform": "pypi", + "version": "4.0.12" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "gitpython-3.1.44-pypi_0", + "name": "gitpython", + "platform": "pypi", + "version": "3.1.44" + }, + { + "base_url": "https://conda.anaconda.org/conda-forge", + "build_number": 2, + "build_string": "hfeafd45_2", + "channel": "conda-forge", + "dist_name": "gmp-6.3.0-hfeafd45_2", + "name": "gmp", + "platform": "win-64", + "version": "6.3.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "google-pasta-0.2.0-pypi_0", + "name": "google-pasta", + "platform": "pypi", + "version": "0.2.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "gputil-1.4.0-pypi_0", + "name": "gputil", + "platform": "pypi", + "version": "1.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "grpcio-1.71.0-pypi_0", + "name": "grpcio", + "platform": "pypi", + "version": "1.71.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "gsplat-1.4.0+pt21cu118-pypi_0", + "name": "gsplat", + "platform": "pypi", + "version": "1.4.0+pt21cu118" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "h11-0.14.0-pypi_0", + "name": "h11", + "platform": "pypi", + "version": "0.14.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "h5py-3.13.0-pypi_0", + "name": "h5py", + "platform": "pypi", + "version": "3.13.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "hf-xet-1.4.3-pypi_0", + "name": "hf-xet", + "platform": "pypi", + "version": "1.4.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "httpcore-1.0.8-pypi_0", + "name": "httpcore", + "platform": "pypi", + "version": "1.0.8" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "httpx-0.28.1-pypi_0", + "name": "httpx", + "platform": "pypi", + "version": "0.28.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "huggingface-hub-0.25.2-pypi_0", + "name": "huggingface-hub", + "platform": "pypi", + "version": "0.25.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "humanfriendly-10.0-pypi_0", + "name": "humanfriendly", + "platform": "pypi", + "version": "10.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 2, + "build_string": "h6049295_2", + "channel": "pkgs/main", + "dist_name": "icc_rt-2022.1.0-h6049295_2", + "name": "icc_rt", + "platform": "win-64", + "version": "2022.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "identify-2.6.18-pypi_0", + "name": "identify", + "platform": "pypi", + "version": "2.6.18" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "idna-3.4-pypi_0", + "name": "idna", + "platform": "pypi", + "version": "3.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "igs2gs-0.1.0-pypi_0", + "name": "igs2gs", + "platform": "pypi", + "version": "0.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "imageio-2.37.0-pypi_0", + "name": "imageio", + "platform": "pypi", + "version": "2.37.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "imageio-ffmpeg-0.6.0-pypi_0", + "name": "imageio-ffmpeg", + "platform": "pypi", + "version": "0.6.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "imagesize-2.0.0-pypi_0", + "name": "imagesize", + "platform": "pypi", + "version": "2.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "importlib-metadata-8.6.1-pypi_0", + "name": "importlib-metadata", + "platform": "pypi", + "version": "8.6.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "iniconfig-2.3.0-pypi_0", + "name": "iniconfig", + "platform": "pypi", + "version": "2.3.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 46320, + "build_string": "h59b6b97_46320", + "channel": "pkgs/main", + "dist_name": "intel-openmp-2023.1.0-h59b6b97_46320", + "name": "intel-openmp", + "platform": "win-64", + "version": "2023.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "ipdb-0.13.13-pypi_0", + "name": "ipdb", + "platform": "pypi", + "version": "0.13.13" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "ipykernel-6.29.5-pypi_0", + "name": "ipykernel", + "platform": "pypi", + "version": "6.29.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "ipython-8.35.0-pypi_0", + "name": "ipython", + "platform": "pypi", + "version": "8.35.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "ipywidgets-8.1.6-pypi_0", + "name": "ipywidgets", + "platform": "pypi", + "version": "8.1.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "isoduration-20.11.0-pypi_0", + "name": "isoduration", + "platform": "pypi", + "version": "20.11.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "itsdangerous-2.2.0-pypi_0", + "name": "itsdangerous", + "platform": "pypi", + "version": "2.2.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jax-0.6.2-pypi_0", + "name": "jax", + "platform": "pypi", + "version": "0.6.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jaxlib-0.6.2-pypi_0", + "name": "jaxlib", + "platform": "pypi", + "version": "0.6.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jaxtyping-0.3.1-pypi_0", + "name": "jaxtyping", + "platform": "pypi", + "version": "0.3.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jedi-0.19.2-pypi_0", + "name": "jedi", + "platform": "pypi", + "version": "0.19.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jinja2-3.1.6-pypi_0", + "name": "jinja2", + "platform": "pypi", + "version": "3.1.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jmespath-1.1.0-pypi_0", + "name": "jmespath", + "platform": "pypi", + "version": "1.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "joblib-1.4.2-pypi_0", + "name": "joblib", + "platform": "pypi", + "version": "1.4.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "json5-0.12.0-pypi_0", + "name": "json5", + "platform": "pypi", + "version": "0.12.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jsonpointer-2.1-pypi_0", + "name": "jsonpointer", + "platform": "pypi", + "version": "2.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jsonschema-4.23.0-pypi_0", + "name": "jsonschema", + "platform": "pypi", + "version": "4.23.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jsonschema-specifications-2024.10.1-pypi_0", + "name": "jsonschema-specifications", + "platform": "pypi", + "version": "2024.10.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyter-1.1.1-pypi_0", + "name": "jupyter", + "platform": "pypi", + "version": "1.1.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyter-client-8.6.3-pypi_0", + "name": "jupyter-client", + "platform": "pypi", + "version": "8.6.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyter-console-6.6.3-pypi_0", + "name": "jupyter-console", + "platform": "pypi", + "version": "6.6.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyter-core-5.7.2-pypi_0", + "name": "jupyter-core", + "platform": "pypi", + "version": "5.7.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyter-events-0.12.0-pypi_0", + "name": "jupyter-events", + "platform": "pypi", + "version": "0.12.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyter-lsp-2.2.5-pypi_0", + "name": "jupyter-lsp", + "platform": "pypi", + "version": "2.2.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyter-server-2.15.0-pypi_0", + "name": "jupyter-server", + "platform": "pypi", + "version": "2.15.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyter-server-terminals-0.5.3-pypi_0", + "name": "jupyter-server-terminals", + "platform": "pypi", + "version": "0.5.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyterlab-4.4.0-pypi_0", + "name": "jupyterlab", + "platform": "pypi", + "version": "4.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyterlab-pygments-0.3.0-pypi_0", + "name": "jupyterlab-pygments", + "platform": "pypi", + "version": "0.3.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyterlab-server-2.27.3-pypi_0", + "name": "jupyterlab-server", + "platform": "pypi", + "version": "2.27.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "jupyterlab-widgets-3.0.14-pypi_0", + "name": "jupyterlab-widgets", + "platform": "pypi", + "version": "3.0.14" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "keras-3.12.1-pypi_0", + "name": "keras", + "platform": "pypi", + "version": "3.12.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "kiwisolver-1.4.8-pypi_0", + "name": "kiwisolver", + "platform": "pypi", + "version": "1.4.8" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "lark-1.3.1-pypi_0", + "name": "lark", + "platform": "pypi", + "version": "1.3.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "latexcodec-3.0.1-pypi_0", + "name": "latexcodec", + "platform": "pypi", + "version": "3.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "lazy-loader-0.4-pypi_0", + "name": "lazy-loader", + "platform": "pypi", + "version": "0.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "lerf-0.1.1-pypi_0", + "name": "lerf", + "platform": "pypi", + "version": "0.1.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "libclang-18.1.1-pypi_0", + "name": "libclang", + "platform": "pypi", + "version": "18.1.1" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libcublas-11.11.3.6-0", + "name": "libcublas", + "platform": "win-64", + "version": "11.11.3.6" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libcublas-dev-11.11.3.6-0", + "name": "libcublas-dev", + "platform": "win-64", + "version": "11.11.3.6" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libcufft-10.9.0.58-0", + "name": "libcufft", + "platform": "win-64", + "version": "10.9.0.58" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libcufft-dev-10.9.0.58-0", + "name": "libcufft-dev", + "platform": "win-64", + "version": "10.9.0.58" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libcurand-10.3.0.86-0", + "name": "libcurand", + "platform": "win-64", + "version": "10.3.0.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libcurand-dev-10.3.0.86-0", + "name": "libcurand-dev", + "platform": "win-64", + "version": "10.3.0.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libcusolver-11.4.1.48-0", + "name": "libcusolver", + "platform": "win-64", + "version": "11.4.1.48" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libcusolver-dev-11.4.1.48-0", + "name": "libcusolver-dev", + "platform": "win-64", + "version": "11.4.1.48" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libcusparse-11.7.5.86-0", + "name": "libcusparse", + "platform": "win-64", + "version": "11.7.5.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libcusparse-dev-11.7.5.86-0", + "name": "libcusparse-dev", + "platform": "win-64", + "version": "11.7.5.86" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 1, + "build_string": "hd77b12b_1", + "channel": "pkgs/main", + "dist_name": "libffi-3.4.4-hd77b12b_1", + "name": "libffi", + "platform": "win-64", + "version": "3.4.4" + }, + { + "base_url": "https://conda.anaconda.org/conda-forge", + "build_number": 18, + "build_string": "h8ee18e1_18", + "channel": "conda-forge", + "dist_name": "libgcc-15.2.0-h8ee18e1_18", + "name": "libgcc", + "platform": "win-64", + "version": "15.2.0" + }, + { + "base_url": "https://conda.anaconda.org/conda-forge", + "build_number": 18, + "build_string": "h8ee18e1_18", + "channel": "conda-forge", + "dist_name": "libgomp-15.2.0-h8ee18e1_18", + "name": "libgomp", + "platform": "win-64", + "version": "15.2.0" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libnpp-11.8.0.86-0", + "name": "libnpp", + "platform": "win-64", + "version": "11.8.0.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libnpp-dev-11.8.0.86-0", + "name": "libnpp-dev", + "platform": "win-64", + "version": "11.8.0.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libnvjpeg-11.9.0.86-0", + "name": "libnvjpeg", + "platform": "win-64", + "version": "11.9.0.86" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "libnvjpeg-dev-11.9.0.86-0", + "name": "libnvjpeg-dev", + "platform": "win-64", + "version": "11.9.0.86" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "h827c3e9_0", + "channel": "pkgs/main", + "dist_name": "libuv-1.48.0-h827c3e9_0", + "name": "libuv", + "platform": "win-64", + "version": "1.48.0" + }, + { + "base_url": "https://conda.anaconda.org/conda-forge", + "build_number": 10, + "build_string": "h57928b3_10", + "channel": "conda-forge", + "dist_name": "libwinpthread-12.0.0.r4.gg4f2fc60ca-h57928b3_10", + "name": "libwinpthread", + "platform": "win-64", + "version": "12.0.0.r4.gg4f2fc60ca" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "lightning-utilities-0.14.3-pypi_0", + "name": "lightning-utilities", + "platform": "pypi", + "version": "0.14.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "livescene-0.1.0-pypi_0", + "name": "livescene", + "platform": "pypi", + "version": "0.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "loguru-0.7.3-pypi_0", + "name": "loguru", + "platform": "pypi", + "version": "0.7.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "lxml-5.2.1-pypi_0", + "name": "lxml", + "platform": "pypi", + "version": "5.2.1" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 1, + "build_string": "h2bbff1b_1", + "channel": "pkgs/main", + "dist_name": "lz4-c-1.9.4-h2bbff1b_1", + "name": "lz4-c", + "platform": "win-64", + "version": "1.9.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "manifold3d-3.0.1-pypi_0", + "name": "manifold3d", + "platform": "pypi", + "version": "3.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "mapbox-earcut-1.0.3-pypi_0", + "name": "mapbox-earcut", + "platform": "pypi", + "version": "1.0.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "markdown-3.8-pypi_0", + "name": "markdown", + "platform": "pypi", + "version": "3.8" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "markdown-it-py-3.0.0-pypi_0", + "name": "markdown-it-py", + "platform": "pypi", + "version": "3.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "markupsafe-3.0.3-pypi_0", + "name": "markupsafe", + "platform": "pypi", + "version": "3.0.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "maskclip-onnx-1.0-pypi_0", + "name": "maskclip-onnx", + "platform": "pypi", + "version": "1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "matplotlib-3.9.2-pypi_0", + "name": "matplotlib", + "platform": "pypi", + "version": "3.9.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "matplotlib-inline-0.1.7-pypi_0", + "name": "matplotlib-inline", + "platform": "pypi", + "version": "0.1.7" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "mdurl-0.1.2-pypi_0", + "name": "mdurl", + "platform": "pypi", + "version": "0.1.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "mediapy-1.2.2-pypi_0", + "name": "mediapy", + "platform": "pypi", + "version": "1.2.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "mistune-3.1.3-pypi_0", + "name": "mistune", + "platform": "pypi", + "version": "3.1.3" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 46358, + "build_string": "h6b88ed4_46358", + "channel": "pkgs/main", + "dist_name": "mkl-2023.1.0-h6b88ed4_46358", + "name": "mkl", + "platform": "win-64", + "version": "2023.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "mkl-service-2.4.0-pypi_0", + "name": "mkl-service", + "platform": "pypi", + "version": "2.4.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "py310h827c3e9_0", + "channel": "pkgs/main", + "dist_name": "mkl_fft-1.3.11-py310h827c3e9_0", + "name": "mkl_fft", + "platform": "win-64", + "version": "1.3.11" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "py310hc64d2fc_0", + "channel": "pkgs/main", + "dist_name": "mkl_random-1.2.8-py310hc64d2fc_0", + "name": "mkl_random", + "platform": "win-64", + "version": "1.2.8" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "ml-dtypes-0.5.4-pypi_0", + "name": "ml-dtypes", + "platform": "pypi", + "version": "0.5.4" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "py310h094160a_0", + "channel": "pkgs/main", + "dist_name": "ml_dtypes-0.5.1-py310h094160a_0", + "name": "ml_dtypes", + "platform": "win-64", + "version": "0.5.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "mobilesamv2-1.0-pypi_0", + "name": "mobilesamv2", + "platform": "pypi", + "version": "1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "mpmath-1.3.0-pypi_0", + "name": "mpmath", + "platform": "pypi", + "version": "1.3.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "msgpack-1.1.0-pypi_0", + "name": "msgpack", + "platform": "pypi", + "version": "1.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "msgpack-numpy-0.4.8-pypi_0", + "name": "msgpack-numpy", + "platform": "pypi", + "version": "0.4.8" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "msgspec-0.19.0-pypi_0", + "name": "msgspec", + "platform": "pypi", + "version": "0.19.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "msvc-runtime-14.42.34433-pypi_0", + "name": "msvc-runtime", + "platform": "pypi", + "version": "14.42.34433" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "multidict-6.7.1-pypi_0", + "name": "multidict", + "platform": "pypi", + "version": "6.7.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "multimethod-2.0.2-pypi_0", + "name": "multimethod", + "platform": "pypi", + "version": "2.0.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "multiprocess-0.70.17-pypi_0", + "name": "multiprocess", + "platform": "pypi", + "version": "0.70.17" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "mypy-extensions-1.1.0-pypi_0", + "name": "mypy-extensions", + "platform": "pypi", + "version": "1.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "namex-0.1.0-pypi_0", + "name": "namex", + "platform": "pypi", + "version": "0.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "narwhals-1.34.1-pypi_0", + "name": "narwhals", + "platform": "pypi", + "version": "1.34.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "nbclient-0.10.2-pypi_0", + "name": "nbclient", + "platform": "pypi", + "version": "0.10.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "nbconvert-7.16.6-pypi_0", + "name": "nbconvert", + "platform": "pypi", + "version": "7.16.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "nbformat-5.10.4-pypi_0", + "name": "nbformat", + "platform": "pypi", + "version": "5.10.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "nerfacc-0.5.2-pypi_0", + "name": "nerfacc", + "platform": "pypi", + "version": "0.5.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "nerfplayer-0.0.2-pypi_0", + "name": "nerfplayer", + "platform": "pypi", + "version": "0.0.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "nerfstudio-1.1.5-pypi_0", + "name": "nerfstudio", + "platform": "pypi", + "version": "1.1.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "nest-asyncio-1.6.0-pypi_0", + "name": "nest-asyncio", + "platform": "pypi", + "version": "1.6.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "networkx-3.4.2-pypi_0", + "name": "networkx", + "platform": "pypi", + "version": "3.4.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "ninja-1.11.1.4-pypi_0", + "name": "ninja", + "platform": "pypi", + "version": "1.11.1.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "nodeenv-1.9.1-pypi_0", + "name": "nodeenv", + "platform": "pypi", + "version": "1.9.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "notebook-7.4.0-pypi_0", + "name": "notebook", + "platform": "pypi", + "version": "7.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "notebook-shim-0.2.4-pypi_0", + "name": "notebook-shim", + "platform": "pypi", + "version": "0.2.4" + }, + { + "base_url": "https://conda.anaconda.org/nvidia/label/cuda-11.8.0", + "build_number": 0, + "build_string": "0", + "channel": "nvidia/label/cuda-11.8.0", + "dist_name": "nsight-compute-2022.3.0.22-0", + "name": "nsight-compute", + "platform": "win-64", + "version": "2022.3.0.22" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "py310h055cbcc_0", + "channel": "pkgs/main", + "dist_name": "numpy-1.26.4-py310h055cbcc_0", + "name": "numpy", + "platform": "win-64", + "version": "1.26.4" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "py310h65a83cf_0", + "channel": "pkgs/main", + "dist_name": "numpy-base-1.26.4-py310h65a83cf_0", + "name": "numpy-base", + "platform": "win-64", + "version": "1.26.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "nuscenes-devkit-1.1.9-pypi_0", + "name": "nuscenes-devkit", + "platform": "pypi", + "version": "1.1.9" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "omegaconf-2.3.0-pypi_0", + "name": "omegaconf", + "platform": "pypi", + "version": "2.3.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "onnx-1.17.0-pypi_0", + "name": "onnx", + "platform": "pypi", + "version": "1.17.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "onnxruntime-1.23.2-pypi_0", + "name": "onnxruntime", + "platform": "pypi", + "version": "1.23.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "onnxsim-0.6.2-pypi_0", + "name": "onnxsim", + "platform": "pypi", + "version": "0.6.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "open-clip-torch-2.32.0-pypi_0", + "name": "open-clip-torch", + "platform": "pypi", + "version": "2.32.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "open3d-0.19.0-pypi_0", + "name": "open3d", + "platform": "pypi", + "version": "0.19.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "opencv-contrib-python-4.11.0.86-pypi_0", + "name": "opencv-contrib-python", + "platform": "pypi", + "version": "4.11.0.86" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "opencv-python-4.11.0.86-pypi_0", + "name": "opencv-python", + "platform": "pypi", + "version": "4.11.0.86" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "opencv-python-headless-4.10.0.84-pypi_0", + "name": "opencv-python-headless", + "platform": "pypi", + "version": "4.10.0.84" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "opencv-stubs-0.0.7-pypi_0", + "name": "opencv-stubs", + "platform": "pypi", + "version": "0.0.7" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "opennerf-0.1.0-pypi_0", + "name": "opennerf", + "platform": "pypi", + "version": "0.1.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "h3f729d1_0", + "channel": "pkgs/main", + "dist_name": "openssl-3.0.16-h3f729d1_0", + "name": "openssl", + "platform": "win-64", + "version": "3.0.16" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "opt-einsum-3.4.0-pypi_0", + "name": "opt-einsum", + "platform": "pypi", + "version": "3.4.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 1, + "build_string": "pyhd3eb1b0_1", + "channel": "pkgs/main", + "dist_name": "opt_einsum-3.3.0-pyhd3eb1b0_1", + "name": "opt_einsum", + "platform": "noarch", + "version": "3.3.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "optix-0.2.3-pypi_0", + "name": "optix", + "platform": "pypi", + "version": "0.2.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "optree-0.19.0-pypi_0", + "name": "optree", + "platform": "pypi", + "version": "0.19.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "overrides-7.7.0-pypi_0", + "name": "overrides", + "platform": "pypi", + "version": "7.7.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "packaging-26.0-pypi_0", + "name": "packaging", + "platform": "pypi", + "version": "26.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pandas-2.2.3-pypi_0", + "name": "pandas", + "platform": "pypi", + "version": "2.2.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pandocfilters-1.5.1-pypi_0", + "name": "pandocfilters", + "platform": "pypi", + "version": "1.5.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "parameterized-0.9.0-pypi_0", + "name": "parameterized", + "platform": "pypi", + "version": "0.9.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "parso-0.8.4-pypi_0", + "name": "parso", + "platform": "pypi", + "version": "0.8.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pathos-0.3.3-pypi_0", + "name": "pathos", + "platform": "pypi", + "version": "0.3.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pathspec-1.0.4-pypi_0", + "name": "pathspec", + "platform": "pypi", + "version": "1.0.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pillow-12.1.1-pypi_0", + "name": "pillow", + "platform": "pypi", + "version": "12.1.1" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "pyhc872135_0", + "channel": "pkgs/main", + "dist_name": "pip-26.0.1-pyhc872135_0", + "name": "pip", + "platform": "noarch", + "version": "26.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pkgconfig-1.6.0-pypi_0", + "name": "pkgconfig", + "platform": "pypi", + "version": "1.6.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "platformdirs-4.3.7-pypi_0", + "name": "platformdirs", + "platform": "pypi", + "version": "4.3.7" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "plotly-6.0.1-pypi_0", + "name": "plotly", + "platform": "pypi", + "version": "6.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pluggy-1.6.0-pypi_0", + "name": "pluggy", + "platform": "pypi", + "version": "1.6.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "plyfile-1.1-pypi_0", + "name": "plyfile", + "platform": "pypi", + "version": "1.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pox-0.3.5-pypi_0", + "name": "pox", + "platform": "pypi", + "version": "0.3.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "ppft-1.7.6.9-pypi_0", + "name": "ppft", + "platform": "pypi", + "version": "1.7.6.9" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pre-commit-3.3.2-pypi_0", + "name": "pre-commit", + "platform": "pypi", + "version": "3.3.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "prometheus-client-0.21.1-pypi_0", + "name": "prometheus-client", + "platform": "pypi", + "version": "0.21.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "prompt-toolkit-3.0.50-pypi_0", + "name": "prompt-toolkit", + "platform": "pypi", + "version": "3.0.50" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "propcache-0.4.1-pypi_0", + "name": "propcache", + "platform": "pypi", + "version": "0.4.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "protobuf-3.20.3-pypi_0", + "name": "protobuf", + "platform": "pypi", + "version": "3.20.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "psutil-7.0.0-pypi_0", + "name": "psutil", + "platform": "pypi", + "version": "7.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pure-eval-0.2.3-pypi_0", + "name": "pure-eval", + "platform": "pypi", + "version": "0.2.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "py-1.11.0-pypi_0", + "name": "py", + "platform": "pypi", + "version": "1.11.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyasn1-0.6.3-pypi_0", + "name": "pyasn1", + "platform": "pypi", + "version": "0.6.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyasn1-modules-0.2.8-pypi_0", + "name": "pyasn1-modules", + "platform": "pypi", + "version": "0.2.8" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pybind11-3.0.3-pypi_0", + "name": "pybind11", + "platform": "pypi", + "version": "3.0.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pybtex-0.26.1-pypi_0", + "name": "pybtex", + "platform": "pypi", + "version": "0.26.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pybtex-docutils-1.0.3-pypi_0", + "name": "pybtex-docutils", + "platform": "pypi", + "version": "1.0.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pycocotools-2.0.8-pypi_0", + "name": "pycocotools", + "platform": "pypi", + "version": "2.0.8" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pycollada-0.9-pypi_0", + "name": "pycollada", + "platform": "pypi", + "version": "0.9" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pycolmap-0.0.1-pypi_0", + "name": "pycolmap", + "platform": "pypi", + "version": "0.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pycparser-2.22-pypi_0", + "name": "pycparser", + "platform": "pypi", + "version": "2.22" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pydantic-2.11.3-pypi_0", + "name": "pydantic", + "platform": "pypi", + "version": "2.11.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pydantic-core-2.33.1-pypi_0", + "name": "pydantic-core", + "platform": "pypi", + "version": "2.33.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyglet-2.1.13-pypi_0", + "name": "pyglet", + "platform": "pypi", + "version": "2.1.13" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pygments-2.19.1-pypi_0", + "name": "pygments", + "platform": "pypi", + "version": "2.19.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyliblzfse-0.4.1-pypi_0", + "name": "pyliblzfse", + "platform": "pypi", + "version": "0.4.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyls-spyder-0.4.0-pypi_0", + "name": "pyls-spyder", + "platform": "pypi", + "version": "0.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pymeshlab-2023.12.post1-pypi_0", + "name": "pymeshlab", + "platform": "pypi", + "version": "2023.12.post1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pynerf-0.1.0-pypi_0", + "name": "pynerf", + "platform": "pypi", + "version": "0.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyngrok-7.2.3-pypi_0", + "name": "pyngrok", + "platform": "pypi", + "version": "7.2.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyopengl-3.1.0-pypi_0", + "name": "pyopengl", + "platform": "pypi", + "version": "3.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyparsing-3.2.3-pypi_0", + "name": "pyparsing", + "platform": "pypi", + "version": "3.2.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyqt5-5.15.10-pypi_0", + "name": "pyqt5", + "platform": "pypi", + "version": "5.15.10" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyqtwebengine-5.15.6-pypi_0", + "name": "pyqtwebengine", + "platform": "pypi", + "version": "5.15.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyquaternion-0.9.9-pypi_0", + "name": "pyquaternion", + "platform": "pypi", + "version": "0.9.9" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyreadline3-3.5.4-pypi_0", + "name": "pyreadline3", + "platform": "pypi", + "version": "3.5.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyrender-0.1.45-pypi_0", + "name": "pyrender", + "platform": "pypi", + "version": "0.1.45" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyright-1.1.331-pypi_0", + "name": "pyright", + "platform": "pypi", + "version": "1.1.331" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pysdf-0.1.9-pypi_0", + "name": "pysdf", + "platform": "pypi", + "version": "0.1.9" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pysocks-1.7.1-pypi_0", + "name": "pysocks", + "platform": "pypi", + "version": "1.7.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pytest-7.1.2-pypi_0", + "name": "pytest", + "platform": "pypi", + "version": "7.1.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pytest-forked-1.6.0-pypi_0", + "name": "pytest-forked", + "platform": "pypi", + "version": "1.6.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pytest-xdist-2.5.0-pypi_0", + "name": "pytest-xdist", + "platform": "pypi", + "version": "2.5.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 1, + "build_string": "h4607a30_1", + "channel": "pkgs/main", + "dist_name": "python-3.10.16-h4607a30_1", + "name": "python", + "platform": "win-64", + "version": "3.10.16" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "python-box-6.1.0-pypi_0", + "name": "python-box", + "platform": "pypi", + "version": "6.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "python-dateutil-2.9.0.post0-pypi_0", + "name": "python-dateutil", + "platform": "pypi", + "version": "2.9.0.post0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "python-discovery-1.2.1-pypi_0", + "name": "python-discovery", + "platform": "pypi", + "version": "1.2.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "python-engineio-4.11.2-pypi_0", + "name": "python-engineio", + "platform": "pypi", + "version": "4.11.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "python-json-logger-3.3.0-pypi_0", + "name": "python-json-logger", + "platform": "pypi", + "version": "3.3.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "python-socketio-5.12.1-pypi_0", + "name": "python-socketio", + "platform": "pypi", + "version": "5.12.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pytokens-0.4.1-pypi_0", + "name": "pytokens", + "platform": "pypi", + "version": "0.4.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pytorch-lightning-1.8.6-pypi_0", + "name": "pytorch-lightning", + "platform": "pypi", + "version": "1.8.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pytorch-msssim-1.0.0-pypi_0", + "name": "pytorch-msssim", + "platform": "pypi", + "version": "1.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pytz-2025.2-pypi_0", + "name": "pytz", + "platform": "pypi", + "version": "2025.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyviz3d-0.5.1-pypi_0", + "name": "pyviz3d", + "platform": "pypi", + "version": "0.5.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pywin32-305-pypi_0", + "name": "pywin32", + "platform": "pypi", + "version": "305" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pywinpty-2.0.15-pypi_0", + "name": "pywinpty", + "platform": "pypi", + "version": "2.0.15" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyyaml-6.0.2-pypi_0", + "name": "pyyaml", + "platform": "pypi", + "version": "6.0.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "pyzmq-26.4.0-pypi_0", + "name": "pyzmq", + "platform": "pypi", + "version": "26.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "rasterio-1.4.4-pypi_0", + "name": "rasterio", + "platform": "pypi", + "version": "1.4.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "rawpy-0.24.0-pypi_0", + "name": "rawpy", + "platform": "pypi", + "version": "0.24.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "referencing-0.36.2-pypi_0", + "name": "referencing", + "platform": "pypi", + "version": "0.36.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "regex-2024.11.6-pypi_0", + "name": "regex", + "platform": "pypi", + "version": "2024.11.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "requests-2.33.1-pypi_0", + "name": "requests", + "platform": "pypi", + "version": "2.33.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "requests-toolbelt-1.0.0-pypi_0", + "name": "requests-toolbelt", + "platform": "pypi", + "version": "1.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "retrying-1.3.4-pypi_0", + "name": "retrying", + "platform": "pypi", + "version": "1.3.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "rfc3339-validator-0.1.4-pypi_0", + "name": "rfc3339-validator", + "platform": "pypi", + "version": "0.1.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "rfc3986-validator-0.1.1-pypi_0", + "name": "rfc3986-validator", + "platform": "pypi", + "version": "0.1.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "rfc3987-syntax-1.1.0-pypi_0", + "name": "rfc3987-syntax", + "platform": "pypi", + "version": "1.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "rich-14.0.0-pypi_0", + "name": "rich", + "platform": "pypi", + "version": "14.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "rpds-py-0.24.0-pypi_0", + "name": "rpds-py", + "platform": "pypi", + "version": "0.24.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "rsa-4.7.2-pypi_0", + "name": "rsa", + "platform": "pypi", + "version": "4.7.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "rtree-1.4.0-pypi_0", + "name": "rtree", + "platform": "pypi", + "version": "1.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "ruff-0.12.2-pypi_0", + "name": "ruff", + "platform": "pypi", + "version": "0.12.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "s3transfer-0.10.4-pypi_0", + "name": "s3transfer", + "platform": "pypi", + "version": "0.10.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "safetensors-0.7.0-pypi_0", + "name": "safetensors", + "platform": "pypi", + "version": "0.7.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "scikit-image-0.25.2-pypi_0", + "name": "scikit-image", + "platform": "pypi", + "version": "0.25.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "scikit-learn-1.6.1-pypi_0", + "name": "scikit-learn", + "platform": "pypi", + "version": "1.6.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "scipy-1.15.2-pypi_0", + "name": "scipy", + "platform": "pypi", + "version": "1.15.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "segment-anything-1.0-pypi_0", + "name": "segment-anything", + "platform": "pypi", + "version": "1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "semantic-version-2.10.0-pypi_0", + "name": "semantic-version", + "platform": "pypi", + "version": "2.10.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "send2trash-1.8.3-pypi_0", + "name": "send2trash", + "platform": "pypi", + "version": "1.8.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sentencepiece-0.1.99-pypi_0", + "name": "sentencepiece", + "platform": "pypi", + "version": "0.1.99" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sentry-sdk-2.25.1-pypi_0", + "name": "sentry-sdk", + "platform": "pypi", + "version": "2.25.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "setproctitle-1.3.5-pypi_0", + "name": "setproctitle", + "platform": "pypi", + "version": "1.3.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "setuptools-75.8.2-pypi_0", + "name": "setuptools", + "platform": "pypi", + "version": "75.8.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "shapely-2.1.0-pypi_0", + "name": "shapely", + "platform": "pypi", + "version": "2.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "shellingham-1.5.4-pypi_0", + "name": "shellingham", + "platform": "pypi", + "version": "1.5.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "shtab-1.7.1-pypi_0", + "name": "shtab", + "platform": "pypi", + "version": "1.7.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "simple-websocket-1.1.0-pypi_0", + "name": "simple-websocket", + "platform": "pypi", + "version": "1.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "simplejson-3.20.1-pypi_0", + "name": "simplejson", + "platform": "pypi", + "version": "3.20.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "six-1.17.0-pypi_0", + "name": "six", + "platform": "pypi", + "version": "1.17.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "smmap-5.0.2-pypi_0", + "name": "smmap", + "platform": "pypi", + "version": "5.0.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sniffio-1.3.1-pypi_0", + "name": "sniffio", + "platform": "pypi", + "version": "1.3.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "snowballstemmer-3.0.1-pypi_0", + "name": "snowballstemmer", + "platform": "pypi", + "version": "3.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "soupsieve-2.6-pypi_0", + "name": "soupsieve", + "platform": "pypi", + "version": "2.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinx-8.1.3-pypi_0", + "name": "sphinx", + "platform": "pypi", + "version": "8.1.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinx-rtd-theme-3.1.0-pypi_0", + "name": "sphinx-rtd-theme", + "platform": "pypi", + "version": "3.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinxcontrib-applehelp-2.0.0-pypi_0", + "name": "sphinxcontrib-applehelp", + "platform": "pypi", + "version": "2.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinxcontrib-bibtex-2.6.5-pypi_0", + "name": "sphinxcontrib-bibtex", + "platform": "pypi", + "version": "2.6.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinxcontrib-devhelp-2.0.0-pypi_0", + "name": "sphinxcontrib-devhelp", + "platform": "pypi", + "version": "2.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinxcontrib-htmlhelp-2.1.0-pypi_0", + "name": "sphinxcontrib-htmlhelp", + "platform": "pypi", + "version": "2.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinxcontrib-jquery-4.1-pypi_0", + "name": "sphinxcontrib-jquery", + "platform": "pypi", + "version": "4.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinxcontrib-jsmath-1.0.1-pypi_0", + "name": "sphinxcontrib-jsmath", + "platform": "pypi", + "version": "1.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinxcontrib-qthelp-2.0.0-pypi_0", + "name": "sphinxcontrib-qthelp", + "platform": "pypi", + "version": "2.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinxcontrib-serializinghtml-2.0.0-pypi_0", + "name": "sphinxcontrib-serializinghtml", + "platform": "pypi", + "version": "2.0.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sphinxcontrib-video-0.4.2-pypi_0", + "name": "sphinxcontrib-video", + "platform": "pypi", + "version": "0.4.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "splatfacto-w-0.1.6-pypi_0", + "name": "splatfacto-w", + "platform": "pypi", + "version": "0.1.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "splines-0.3.0-pypi_0", + "name": "splines", + "platform": "pypi", + "version": "0.3.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "h2bbff1b_0", + "channel": "pkgs/main", + "dist_name": "sqlite-3.45.3-h2bbff1b_0", + "name": "sqlite", + "platform": "win-64", + "version": "3.45.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sshconf-0.2.5-pypi_0", + "name": "sshconf", + "platform": "pypi", + "version": "0.2.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "stack-data-0.6.3-pypi_0", + "name": "stack-data", + "platform": "pypi", + "version": "0.6.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "svg-path-6.3-pypi_0", + "name": "svg-path", + "platform": "pypi", + "version": "6.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "sympy-1.14.0-pypi_0", + "name": "sympy", + "platform": "pypi", + "version": "1.14.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tabulate-0.10.0-pypi_0", + "name": "tabulate", + "platform": "pypi", + "version": "0.10.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "taichi-1.7.4-pypi_0", + "name": "taichi", + "platform": "pypi", + "version": "1.7.4" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "h59b6b97_0", + "channel": "pkgs/main", + "dist_name": "tbb-2021.8.0-h59b6b97_0", + "name": "tbb", + "platform": "win-64", + "version": "2021.8.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tensorboard-2.19.0-pypi_0", + "name": "tensorboard", + "platform": "pypi", + "version": "2.19.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tensorboard-data-server-0.7.2-pypi_0", + "name": "tensorboard-data-server", + "platform": "pypi", + "version": "0.7.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tensorboardx-2.6.2.2-pypi_0", + "name": "tensorboardx", + "platform": "pypi", + "version": "2.6.2.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tensorflow-2.19.1-pypi_0", + "name": "tensorflow", + "platform": "pypi", + "version": "2.19.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tensorflow-io-gcs-filesystem-0.31.0-pypi_0", + "name": "tensorflow-io-gcs-filesystem", + "platform": "pypi", + "version": "0.31.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tensorly-0.9.0-pypi_0", + "name": "tensorly", + "platform": "pypi", + "version": "0.9.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tensorpack-0.11-pypi_0", + "name": "tensorpack", + "platform": "pypi", + "version": "0.11" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "termcolor-3.0.1-pypi_0", + "name": "termcolor", + "platform": "pypi", + "version": "3.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "terminado-0.18.1-pypi_0", + "name": "terminado", + "platform": "pypi", + "version": "0.18.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tetra-nerf-0.1.1-pypi_0", + "name": "tetra-nerf", + "platform": "pypi", + "version": "0.1.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "threadpoolctl-3.6.0-pypi_0", + "name": "threadpoolctl", + "platform": "pypi", + "version": "3.6.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tifffile-2025.3.30-pypi_0", + "name": "tifffile", + "platform": "pypi", + "version": "2025.3.30" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "timm-0.6.7-pypi_0", + "name": "timm", + "platform": "pypi", + "version": "0.6.7" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tinycss2-1.4.0-pypi_0", + "name": "tinycss2", + "platform": "pypi", + "version": "1.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tinycudann-2.0-pypi_0", + "name": "tinycudann", + "platform": "pypi", + "version": "2.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "h0416ee5_0", + "channel": "pkgs/main", + "dist_name": "tk-8.6.14-h0416ee5_0", + "name": "tk", + "platform": "win-64", + "version": "8.6.14" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tokenizers-0.13.3-pypi_0", + "name": "tokenizers", + "platform": "pypi", + "version": "0.13.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "toml-0.10.2-pypi_0", + "name": "toml", + "platform": "pypi", + "version": "0.10.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tomli-2.2.1-pypi_0", + "name": "tomli", + "platform": "pypi", + "version": "2.2.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "torch-2.1.2+cu118-pypi_0", + "name": "torch", + "platform": "pypi", + "version": "2.1.2+cu118" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "torch-fidelity-0.3.0-pypi_0", + "name": "torch-fidelity", + "platform": "pypi", + "version": "0.3.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "torch-scatter-2.1.2+pt21cu118-pypi_0", + "name": "torch-scatter", + "platform": "pypi", + "version": "2.1.2+pt21cu118" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "torchaudio-2.1.2+cu118-pypi_0", + "name": "torchaudio", + "platform": "pypi", + "version": "2.1.2+cu118" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "torchmetrics-1.7.1-pypi_0", + "name": "torchmetrics", + "platform": "pypi", + "version": "1.7.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "torchpack-0.3.1-pypi_0", + "name": "torchpack", + "platform": "pypi", + "version": "0.3.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "torchtyping-0.1.5-pypi_0", + "name": "torchtyping", + "platform": "pypi", + "version": "0.1.5" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "torchvision-0.16.2+cu118-pypi_0", + "name": "torchvision", + "platform": "pypi", + "version": "0.16.2+cu118" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tornado-6.4.2-pypi_0", + "name": "tornado", + "platform": "pypi", + "version": "6.4.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tqdm-4.67.1-pypi_0", + "name": "tqdm", + "platform": "pypi", + "version": "4.67.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "traitlets-5.14.3-pypi_0", + "name": "traitlets", + "platform": "pypi", + "version": "5.14.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "transformers-4.29.2-pypi_0", + "name": "transformers", + "platform": "pypi", + "version": "4.29.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "trimesh-4.6.6-pypi_0", + "name": "trimesh", + "platform": "pypi", + "version": "4.6.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "typeguard-4.5.1-pypi_0", + "name": "typeguard", + "platform": "pypi", + "version": "4.5.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "typer-0.24.1-pypi_0", + "name": "typer", + "platform": "pypi", + "version": "0.24.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "types-python-dateutil-2.9.0.20241206-pypi_0", + "name": "types-python-dateutil", + "platform": "pypi", + "version": "2.9.0.20241206" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "typing-extensions-4.15.0-pypi_0", + "name": "typing-extensions", + "platform": "pypi", + "version": "4.15.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "typing-inspection-0.4.0-pypi_0", + "name": "typing-inspection", + "platform": "pypi", + "version": "0.4.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tyro-0.9.8-pypi_0", + "name": "tyro", + "platform": "pypi", + "version": "0.9.8" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "tzdata-2025.2-pypi_0", + "name": "tzdata", + "platform": "pypi", + "version": "2025.2" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "haa95532_0", + "channel": "pkgs/main", + "dist_name": "ucrt-10.0.22621.0-haa95532_0", + "name": "ucrt", + "platform": "win-64", + "version": "10.0.22621.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "uri-template-1.3.0-pypi_0", + "name": "uri-template", + "platform": "pypi", + "version": "1.3.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "urllib3-1.26.13-pypi_0", + "name": "urllib3", + "platform": "pypi", + "version": "1.26.13" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 4, + "build_string": "haa95532_4", + "channel": "pkgs/main", + "dist_name": "vc-14.42-haa95532_4", + "name": "vc", + "platform": "win-64", + "version": "14.42" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "vhacdx-0.0.8.post2-pypi_0", + "name": "vhacdx", + "platform": "pypi", + "version": "0.0.8.post2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "virtualenv-21.2.0-pypi_0", + "name": "virtualenv", + "platform": "pypi", + "version": "21.2.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "viser-1.0.0-pypi_0", + "name": "viser", + "platform": "pypi", + "version": "1.0.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 4, + "build_string": "he0abc0d_4", + "channel": "pkgs/main", + "dist_name": "vs2015_runtime-14.42.34433-he0abc0d_4", + "name": "vs2015_runtime", + "platform": "win-64", + "version": "14.42.34433" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "wadler-lindig-0.1.4-pypi_0", + "name": "wadler-lindig", + "platform": "pypi", + "version": "0.1.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "wandb-0.19.9-pypi_0", + "name": "wandb", + "platform": "pypi", + "version": "0.19.9" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "wcwidth-0.2.13-pypi_0", + "name": "wcwidth", + "platform": "pypi", + "version": "0.2.13" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "webcolors-24.11.1-pypi_0", + "name": "webcolors", + "platform": "pypi", + "version": "24.11.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "webencodings-0.5.1-pypi_0", + "name": "webencodings", + "platform": "pypi", + "version": "0.5.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "websocket-client-1.8.0-pypi_0", + "name": "websocket-client", + "platform": "pypi", + "version": "1.8.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "websockets-15.0.1-pypi_0", + "name": "websockets", + "platform": "pypi", + "version": "15.0.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "werkzeug-3.0.6-pypi_0", + "name": "werkzeug", + "platform": "pypi", + "version": "3.0.6" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "wheel-0.46.3-pypi_0", + "name": "wheel", + "platform": "pypi", + "version": "0.46.3" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "widgetsnbextension-4.0.14-pypi_0", + "name": "widgetsnbextension", + "platform": "pypi", + "version": "4.0.14" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "win32-setctime-1.2.0-pypi_0", + "name": "win32-setctime", + "platform": "pypi", + "version": "1.2.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "wrapt-1.17.2-pypi_0", + "name": "wrapt", + "platform": "pypi", + "version": "1.17.2" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "wsproto-1.2.0-pypi_0", + "name": "wsproto", + "platform": "pypi", + "version": "1.2.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "wurlitzer-3.1.1-pypi_0", + "name": "wurlitzer", + "platform": "pypi", + "version": "3.1.1" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "xatlas-0.0.10-pypi_0", + "name": "xatlas", + "platform": "pypi", + "version": "0.0.10" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "xxhash-3.5.0-pypi_0", + "name": "xxhash", + "platform": "pypi", + "version": "3.5.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 1, + "build_string": "h4754444_1", + "channel": "pkgs/main", + "dist_name": "xz-5.6.4-h4754444_1", + "name": "xz", + "platform": "win-64", + "version": "5.6.4" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "yarl-1.23.0-pypi_0", + "name": "yarl", + "platform": "pypi", + "version": "1.23.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "yourdfpy-0.0.57-pypi_0", + "name": "yourdfpy", + "platform": "pypi", + "version": "0.0.57" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "zipnerf-0.1.0-pypi_0", + "name": "zipnerf", + "platform": "pypi", + "version": "0.1.0" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "zipp-3.21.0-pypi_0", + "name": "zipp", + "platform": "pypi", + "version": "3.21.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 1, + "build_string": "h8cc25b3_1", + "channel": "pkgs/main", + "dist_name": "zlib-1.2.13-h8cc25b3_1", + "name": "zlib", + "platform": "win-64", + "version": "1.2.13" + }, + { + "base_url": "https://conda.anaconda.org/pypi", + "build_number": 0, + "build_string": "pypi_0", + "channel": "pypi", + "dist_name": "zstandard-0.25.0-pypi_0", + "name": "zstandard", + "platform": "pypi", + "version": "0.25.0" + }, + { + "base_url": "https://repo.anaconda.com/pkgs/main", + "build_number": 0, + "build_string": "h8880b57_0", + "channel": "pkgs/main", + "dist_name": "zstd-1.5.6-h8880b57_0", + "name": "zstd", + "platform": "win-64", + "version": "1.5.6" + } +] \ No newline at end of file diff --git a/deps-lock/installer-selection.json b/deps-lock/installer-selection.json new file mode 100644 index 0000000000..a30ba66978 --- /dev/null +++ b/deps-lock/installer-selection.json @@ -0,0 +1,12 @@ +{ + "cuda_arch": "86", + "tcnn_cuda_architectures": "86", + "gpu_name": "manual", + "preferred_msvc": "14.38", + "preferred_msvc_mode": "14.38", + "selected_msvc_toolset_hint": "14.38.33130", + "selected_msvc_installation_hint": "C:\\PROGRA~1\\MICROS~1\\2022\\PROFES~1", + "conda_mode": "current", + "conda_root": "C:\\Users\\crist\\Documenti\\nerfstudio_custom\\.conda", + "written_utc": "2026-04-08T19:21:39.771925+00:00" +} diff --git a/deps-lock/lock-meta.json b/deps-lock/lock-meta.json new file mode 100644 index 0000000000..0ff744c34e --- /dev/null +++ b/deps-lock/lock-meta.json @@ -0,0 +1,19 @@ +{ + "created_utc": "2026-04-08T19:21:59.082644+00:00", + "python_executable": "C:\\Users\\crist\\Documenti\\nerfstudio_custom\\.conda\\python.exe", + "python_version": "3.10.16 | packaged by Anaconda, Inc. | (main, Dec 11 2024, 16:19:12) [MSC v.1929 64 bit (AMD64)]", + "platform_guess": "win-64", + "conda_executable": "C:\\Users\\crist\\Documenti\\nerfstudio_custom\\.conda\\Scripts\\conda.exe", + "conda_env": "nerfstudio-portable", + "conda_prefix": "C:\\Users\\crist\\Documenti\\nerfstudio_custom\\.conda\\envs\\nerfstudio-portable", + "conda_lock": "conda-explicit-win-64.txt", + "pip_lock": "pip-freeze-all.txt", + "pip_replay": "pip-freeze-replay.txt", + "build_plan": "build-plan.json", + "numpy_audit": "numpy-compat-audit.txt", + "nerfstudio_methods_protected": "nerfstudio-methods-protected.json", + "nerfstudio_core_overrides": "nerfstudio-core-overrides.json", + "msvc_log": "msvc-toolsets.txt", + "msvc_selected_log": "msvc-selected.txt", + "installer_selection": "installer-selection.json" +} diff --git a/deps-lock/msvc-selected.txt b/deps-lock/msvc-selected.txt new file mode 100644 index 0000000000..d96fb72cfc --- /dev/null +++ b/deps-lock/msvc-selected.txt @@ -0,0 +1,16 @@ +requested=14.38 +cuda_mode=vanilla +cuda_root=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8 +git_dirs=C:\Program Files\Git\cmd;C:\Program Files\Git\bin +runtime_path_entries=C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable\Scripts;C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable;C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable\Library\bin;C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable\Library\usr\bin;C:\Users\crist\Documenti\nerfstudio_custom\.conda\envs\nerfstudio-portable\bin;C:\Users\crist\Documents\nerfstudio_custom\.conda\envs\nerfstudio-portable;C:\Program Files\Git\cmd;C:\Program Files\Git\bin +include=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\include;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\VS\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\winrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\cppwinrt;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um +lib=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\lib\x64;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\lib\um\x64;C:\Program Files (x86)\Windows Kits\10\lib\10.0.26100.0\ucrt\x64;C:\Program Files (x86)\Windows Kits\10\lib\10.0.26100.0\um\x64 +libpath=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\lib\x64;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\lib\x86\store\references;C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.26100.0;C:\Program Files (x86)\Windows Kits\10\References\10.0.26100.0;C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319 +winsdk=C:\Program Files (x86)\Windows Kits\10 +ucrt=C:\Program Files (x86)\Windows Kits\10 +selected_toolset=14.38.33130 +selected_short=14.38 +selected_install=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools +selected_cl=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\bin\Hostx64\x64\cl.exe +selected_vcvarsall=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat +mode=subprocess-shell-bootstrap diff --git a/deps-lock/msvc-toolsets.txt b/deps-lock/msvc-toolsets.txt new file mode 100644 index 0000000000..684a66daf8 --- /dev/null +++ b/deps-lock/msvc-toolsets.txt @@ -0,0 +1,11 @@ +Detected MSVC toolsets: +14.44.35207 | short=14.44 | install=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools | cl=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x64\cl.exe | vcvarsall=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat +14.44.35207 | short=14.44 | install=C:\Program Files\Microsoft Visual Studio\2022\Professional | cl=C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x64\cl.exe | vcvarsall=C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat +14.38.33130 | short=14.38 | install=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools | cl=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.38.33130\bin\Hostx64\x64\cl.exe | vcvarsall=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat +14.38.33130 | short=14.38 | install=C:\Program Files\Microsoft Visual Studio\2022\Professional | cl=C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.38.33130\bin\Hostx64\x64\cl.exe | vcvarsall=C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat +14.29.30133 | short=14.29 | install=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community | cl=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe | vcvarsall=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat +14.29.30133 | short=14.29 | install=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools | cl=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe | vcvarsall=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat +14.29.30133 | short=14.29 | install=C:\Program Files\Microsoft Visual Studio\2022\Professional | cl=C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.29.30133\bin\Hostx64\x64\cl.exe | vcvarsall=C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat +14.16.27023 | short=14.16 | install=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools | cl=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe | vcvarsall=C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat +14.16.27023 | short=14.16 | install=C:\Program Files\Microsoft Visual Studio\2022\Professional | cl=C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe | vcvarsall=C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvarsall.bat +14.16.27023 | short=14.16 | install=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community | cl=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\Hostx64\x64\cl.exe | vcvarsall=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat diff --git a/deps-lock/nerfstudio-core-overrides.json b/deps-lock/nerfstudio-core-overrides.json new file mode 100644 index 0000000000..94a6a00707 --- /dev/null +++ b/deps-lock/nerfstudio-core-overrides.json @@ -0,0 +1,15 @@ +{ + "core_overrides": { + "pycolmap": { + "install_ref": "git+https://github.com/rmbrualla/pycolmap.git", + "patch_rel": null, + "pip_names": [ + "pycolmap" + ], + "category": "core_dependency", + "enforce_as_standard": true, + "locked_requirement": "pycolmap @ git+https://github.com/rmbrualla/pycolmap.git@cc7ea4b7301720ac29287dbe450952511b32125e", + "present_in_lock": true + } + } +} diff --git a/deps-lock/nerfstudio-methods-protected.json b/deps-lock/nerfstudio-methods-protected.json new file mode 100644 index 0000000000..92ea1157b5 --- /dev/null +++ b/deps-lock/nerfstudio-methods-protected.json @@ -0,0 +1,108 @@ +{ + "protected_methods": { + "feature-splatting": { + "install_ref": "git+https://github.com/vuer-ai/feature-splatting", + "patch_rel": "feature-splatting", + "pip_names": [ + "feature-splatting", + "feature_splatting" + ], + "category": "method", + "locked_requirement": "", + "present_in_lock": false + }, + "igs2gs": { + "install_ref": "git+https://github.com/cvachha/instruct-gs2gs", + "patch_rel": "igs2gs", + "pip_names": [ + "igs2gs" + ], + "category": "method", + "locked_requirement": "", + "present_in_lock": false + }, + "lerf": { + "install_ref": "git+https://github.com/kerrj/lerf", + "patch_rel": "lerf", + "pip_names": [ + "lerf" + ], + "category": "method", + "locked_requirement": "", + "present_in_lock": false + }, + "livescene": { + "install_ref": "git+https://github.com/Tavish9/livescene", + "patch_rel": "livescene", + "pip_names": [ + "livescene" + ], + "category": "method", + "locked_requirement": "", + "present_in_lock": false + }, + "nerfplayer": { + "install_ref": "git+https://github.com/lsongx/nerfplayer-nerfstudio.git", + "patch_rel": "nerfplayer", + "pip_names": [ + "nerfplayer" + ], + "category": "method", + "locked_requirement": "", + "present_in_lock": false + }, + "opennerf": { + "install_ref": "git+https://github.com/opennerf/opennerf", + "patch_rel": "opennerf", + "pip_names": [ + "opennerf" + ], + "category": "method", + "locked_requirement": "", + "present_in_lock": false + }, + "pynerf": { + "install_ref": "git+https://github.com/hturki/pynerf", + "patch_rel": "pynerf", + "pip_names": [ + "pynerf" + ], + "category": "method", + "locked_requirement": "", + "present_in_lock": false + }, + "splatfacto-w": { + "install_ref": "git+https://github.com/KevinXu02/splatfacto-w", + "patch_rel": "splatfacto-w", + "pip_names": [ + "splatfacto-w", + "splatfactow" + ], + "category": "method", + "locked_requirement": "", + "present_in_lock": false + }, + "tetra-nerf": { + "install_ref": "git+https://github.com/jkulhanek/tetra-nerf", + "patch_rel": "tetra-nerf", + "pip_names": [ + "tetra-nerf", + "tetra_nerf" + ], + "category": "method", + "locked_requirement": "", + "present_in_lock": false + }, + "zipnerf-pytorch": { + "install_ref": "git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git", + "patch_rel": "zipnerf-pytorch", + "pip_names": [ + "zipnerf", + "zipnerf-pytorch" + ], + "category": "method", + "locked_requirement": "", + "present_in_lock": false + } + } +} diff --git a/deps-lock/numpy-compat-audit.txt b/deps-lock/numpy-compat-audit.txt new file mode 100644 index 0000000000..6457f9b4e1 --- /dev/null +++ b/deps-lock/numpy-compat-audit.txt @@ -0,0 +1,8 @@ +matplotlib==3.9.2 +numpy==1.26.4 +pycolmap @ git+https://github.com/rmbrualla/pycolmap.git@cc7ea4b7301720ac29287dbe450952511b32125e +torch==2.1.2+cu118 +torchvision==0.16.2+cu118 +PLAN torch_preinstall: torch==2.1.2+cu118 +PLAN torch_preinstall: torchvision==0.16.2+cu118 +PLAN deferred: tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@6ee3546bda615f51abe684ce9edefeb414689135#subdirectory=bindings/torch diff --git a/deps-lock/pip-freeze-all.txt b/deps-lock/pip-freeze-all.txt new file mode 100644 index 0000000000..7fa1b91343 --- /dev/null +++ b/deps-lock/pip-freeze-all.txt @@ -0,0 +1,67 @@ +anaconda-anon-usage @ file:///C:/b/abs_e8r_zga7xy/croot/anaconda-anon-usage_1732732454901/work +appdirs==1.4.4 +archspec @ file:///croot/archspec_1709217642129/work +atomicwrites==1.4.0 +boltons @ file:///C:/b/abs_707eo7c09t/croot/boltons_1677628723117/work +Brotli @ file:///C:/b/abs_3d36mno480/croot/brotli-split_1714483178642/work +certifi==2022.12.7 +cffi @ file:///C:/b/abs_90yq4lmu83/croot/cffi_1726856448345/work +charset-normalizer==2.1.1 +colorama @ file:///C:/b/abs_a9ozq0l032/croot/colorama_1672387194846/work +conda @ file:///C:/b/abs_3bs4tei4e9/croot/conda_1733841834375/work +conda-anaconda-telemetry @ file:///C:/b/abs_b5wbfhyt0i/croot/conda-anaconda-telemetry_1733260551861/work +conda-content-trust @ file:///C:/b/abs_bdfatn_wzf/croot/conda-content-trust_1714483201909/work +conda-libmamba-solver @ file:///croot/conda-libmamba-solver_1727775630457/work/src +conda-package-handling @ file:///C:/b/abs_7fz3aferfv/croot/conda-package-handling_1731369038903/work +conda_package_streaming @ file:///C:/b/abs_bdz9vbvbh2/croot/conda-package-streaming_1731366449946/work +cryptography @ file:///C:/b/abs_e2lzchf4i6/croot/cryptography_1732130411942/work +Cython==3.2.4 +distro @ file:///C:/b/abs_71xr36ua5r/croot/distro_1714488282676/work +filelock==3.25.2 +frozendict @ file:///C:/b/abs_2alamqss6p/croot/frozendict_1713194885124/work +fsspec==2026.2.0 +idna==3.4 +Jinja2==3.1.6 +jsonpatch @ file:///C:/b/abs_4fdm88t7zi/croot/jsonpatch_1714483974578/work +jsonpointer==2.1 +libmambapy @ file:///C:/b/abs_7fjjcok9fe/croot/mamba-split_1732896315069/work/libmambapy +lxml==5.2.1 +MarkupSafe==3.0.3 +matplotlib==3.9.2 +menuinst @ file:///C:/b/abs_cabvzz4p7a/croot/menuinst_1731364936347/work +mkl-service==2.4.0 +mpmath==1.3.0 +networkx==3.4.2 +numpy==1.26.4 +packaging==26.0 +pillow==12.1.1 +pip==26.0.1 +pkgconfig==1.6.0 +platformdirs @ file:///C:/b/abs_b6z_yqw_ii/croot/platformdirs_1692205479426/work +pluggy @ file:///C:/b/abs_dfec_m79vo/croot/pluggy_1733170145382/work +protobuf==4.25.3 +pyasn1-modules==0.2.8 +pybind11==3.0.3 +pycolmap @ git+https://github.com/rmbrualla/pycolmap.git@cc7ea4b7301720ac29287dbe450952511b32125e +pycosat @ file:///C:/b/abs_5csdern___/croot/pycosat_1714513102923/work +pycparser @ file:///tmp/build/80754af9/pycparser_1636541352034/work +pyls-spyder==0.4.0 +PyQt5==5.15.10 +PyQtWebEngine==5.15.6 +PySocks @ file:///C:/ci_310/pysocks_1642089375450/work +pywin32==305 +requests==2.28.1 +ruamel.yaml @ file:///C:/b/abs_0cunwx_ww6/croot/ruamel.yaml_1727980181547/work +ruamel.yaml.clib @ file:///C:/b/abs_5fk8zi6n09/croot/ruamel.yaml.clib_1727769837359/work +setuptools==75.1.0 +sympy==1.14.0 +tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@6ee3546bda615f51abe684ce9edefeb414689135#subdirectory=bindings/torch +torch==2.1.2+cu118 +torchvision==0.16.2+cu118 +tqdm @ file:///C:/b/abs_77wju137gk/croot/tqdm_1724853945787/work +truststore @ file:///C:/b/abs_55z7b3r045/croot/truststore_1695245455435/work +typing_extensions==4.15.0 +urllib3==1.26.13 +wheel==0.44.0 +win-inet-pton @ file:///C:/ci_310/win_inet_pton_1642658466512/work +zstandard @ file:///C:/b/abs_31t8xmrv_h/croot/zstandard_1731356578015/work diff --git a/deps-lock/pip-freeze-replay.txt b/deps-lock/pip-freeze-replay.txt new file mode 100644 index 0000000000..b3011727f0 --- /dev/null +++ b/deps-lock/pip-freeze-replay.txt @@ -0,0 +1,33 @@ +appdirs==1.4.4 +atomicwrites==1.4.0 +certifi==2022.12.7 +charset-normalizer==2.1.1 +Cython==3.2.4 +filelock==3.25.2 +fsspec==2026.2.0 +idna==3.4 +Jinja2==3.1.6 +jsonpointer==2.1 +lxml==5.2.1 +MarkupSafe==3.0.3 +matplotlib==3.9.2 +mkl-service==2.4.0 +mpmath==1.3.0 +networkx==3.4.2 +packaging==26.0 +pillow==12.1.1 +pip==26.0.1 +pkgconfig==1.6.0 +protobuf==4.25.3 +pyasn1-modules==0.2.8 +pybind11==3.0.3 +pyls-spyder==0.4.0 +PyQt5==5.15.10 +PyQtWebEngine==5.15.6 +pywin32==305 +requests==2.28.1 +setuptools==75.1.0 +sympy==1.14.0 +typing_extensions==4.15.0 +urllib3==1.26.13 +wheel==0.44.0 diff --git a/deps_lock.py b/deps_lock.py new file mode 100644 index 0000000000..5e7c3c62ef --- /dev/null +++ b/deps_lock.py @@ -0,0 +1,2142 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import json +import os +import platform +import re +import shutil +import subprocess +import sys +import tempfile +from datetime import datetime, timezone +from pathlib import Path +from typing import Optional + +ROOT = Path(__file__).resolve().parent +DEFAULT_LOCK_DIR = ROOT / "deps-lock" +DEFAULT_NUMPY = "numpy==1.26.4" +DEFAULT_TORCH = [ + "torch==2.1.2+cu118", + "torchvision==0.16.2+cu118", +] +TORCH_INDEX = "https://download.pytorch.org/whl/cu118" +PYG_INDEX_TEMPLATE = "https://data.pyg.org/whl/{torch_tag}.html" +TCNN_GIT = "git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch" +PIP_VERBOSE_ARGS = ["-v"] +PYCOLMAP_GIT = "git+https://github.com/rmbrualla/pycolmap.git" + +PROTECTED_NAMES = { + "numpy", + "torch", + "torchvision", + "torchaudio", + "tinycudann", + "tiny-cuda-nn", + "torch-scatter", + "torch-sparse", + "torch-cluster", + "torch-spline-conv", + "nerfstudio", + "nerfacc", + "gsplat", + "viser", + "huggingface-hub", + "bitsandbytes", + "tyro", + "opencv-python", + "opencv-contrib-python", + "pycolmap", + "cuda-backend", + "protobuf", + "matplotlib", +} + +PROTECTED_PACKAGES = { + "numpy", + "torch", + "torchvision", + "torchaudio", + "tinycudann", + "nerfstudio", + "nerfacc", + "gsplat", + "viser", + "huggingface-hub", + "huggingface_hub", + "bitsandbytes", + "tyro", + "protobuf", + "matplotlib", + "torch-scatter", + "torch_scatter", +} + +PROTECTED_GIT_PACKAGES = { + "tinycudann": TCNN_GIT, + "tiny-cuda-nn": TCNN_GIT, + "pycolmap": PYCOLMAP_GIT, +} + + +# Nerfstudio extra methods/plugins that should be managed outside the core +# freeze/restore flow. These are intentionally severed from the generic pip +# replay so a custom installer (for example extras_portable_manager.bat) can +# install them in a controlled order and apply repo-relative patches. +NERFSTUDIO_METHODS_PROTECTED = { + "feature-splatting": { + "pip_names": {"feature-splatting", "feature_splatting"}, + "install_ref": "git+https://github.com/vuer-ai/feature-splatting", + "patch_rel": "feature-splatting", + "category": "method", + }, + "igs2gs": { + "pip_names": {"igs2gs"}, + "install_ref": "git+https://github.com/cvachha/instruct-gs2gs", + "patch_rel": "igs2gs", + "category": "method", + }, + "lerf": { + "pip_names": {"lerf"}, + "install_ref": "git+https://github.com/kerrj/lerf", + "patch_rel": "lerf", + "category": "method", + }, + "livescene": { + "pip_names": {"livescene"}, + "install_ref": "git+https://github.com/Tavish9/livescene", + "patch_rel": "livescene", + "category": "method", + }, + "nerfplayer": { + "pip_names": {"nerfplayer"}, + "install_ref": "git+https://github.com/lsongx/nerfplayer-nerfstudio.git", + "patch_rel": "nerfplayer", + "category": "method", + }, + "opennerf": { + "pip_names": {"opennerf"}, + "install_ref": "git+https://github.com/opennerf/opennerf", + "patch_rel": "opennerf", + "category": "method", + }, + "pynerf": { + "pip_names": {"pynerf"}, + "install_ref": "git+https://github.com/hturki/pynerf", + "patch_rel": "pynerf", + "category": "method", + }, + "splatfacto-w": { + "pip_names": {"splatfacto-w", "splatfactow"}, + "install_ref": "git+https://github.com/KevinXu02/splatfacto-w", + "patch_rel": "splatfacto-w", + "category": "method", + }, + "tetra-nerf": { + "pip_names": {"tetra-nerf", "tetra_nerf"}, + "install_ref": "git+https://github.com/jkulhanek/tetra-nerf", + "patch_rel": "tetra-nerf", + "category": "method", + }, + "zipnerf-pytorch": { + "pip_names": {"zipnerf", "zipnerf-pytorch"}, + "install_ref": "git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git", + "patch_rel": "zipnerf-pytorch", + "category": "method", + }, +} + +NERFSTUDIO_CORE_OVERRIDES = { + "pycolmap": { + "pip_names": {"pycolmap"}, + "install_ref": PYCOLMAP_GIT, + "patch_rel": None, + "category": "core_dependency", + "enforce_as_standard": True, + }, +} + +NERFSTUDIO_METHODS_PROTECTED_NAMES = { + alias + for spec in NERFSTUDIO_METHODS_PROTECTED.values() + for alias in spec["pip_names"] +} + +NERFSTUDIO_CORE_OVERRIDE_NAMES = { + alias + for spec in NERFSTUDIO_CORE_OVERRIDES.values() + for alias in spec["pip_names"] +} + +BUILD_TOOL_PKGS = [ + "pip", + "setuptools", + "wheel", + "Cython", + "pkgconfig", + "pybind11", +] + +STRICT_ALIGNMENT_NAMES = [ + "numpy", + "torch", + "torchvision", + "torchaudio", + "tinycudann", + "nerfstudio", + "nerfacc", + "gsplat", + "viser", + "huggingface-hub", + "bitsandbytes", + "tyro", + "pycolmap", + "protobuf", + "matplotlib", + "torch-scatter", +] + +TORCH_LINE_RE = re.compile(r"^(torch|torchvision|torchaudio)==", re.I) +PYG_LINE_RE = re.compile(r"^torch[-_](scatter|sparse|cluster|spline[-_]conv)==", re.I) +AV_LINE_RE = re.compile(r"^av==", re.I) +PYWIN32_BAD_RE = re.compile(r"^pywin32==305\.1$", re.I) +TCNN_REQ_RE = re.compile(r"^(tinycudann|tiny-cuda-nn)(==|\s*@\s*)", re.I) + +SKIP_PATTERNS = [ + re.compile(r"^-e\s+\.", re.I), + re.compile(r"^-e\s+.+nerfstudio", re.I), + re.compile(r"^\S+\s*@\s*file:///", re.I), + re.compile(r"^cuda_backend==", re.I), + re.compile(r"^av==", re.I), + re.compile(r"^torch==", re.I), + re.compile(r"^torchvision==", re.I), + re.compile(r"^torchaudio==", re.I), + re.compile(r"^torch[-_]scatter==", re.I), + re.compile(r"^torch[-_]sparse==", re.I), + re.compile(r"^torch[-_]cluster==", re.I), + re.compile(r"^torch[-_]spline[-_]conv==", re.I), + re.compile(r"^numpy(==|<|<=|>=|>|~=)", re.I), +] +DEFER_PATTERNS = [ + re.compile(r"^tinycudann\s*@\s*git\+https://github.com/NVlabs/tiny-cuda-nn/", re.I), + re.compile(r"^tiny-cuda-nn\s*@\s*git\+https://github.com/NVlabs/tiny-cuda-nn/", re.I), + re.compile(r"^tinycudann==", re.I), + re.compile(r"^tiny-cuda-nn==", re.I), +] + + +def run( + cmd: list[str], + *, + check: bool = True, + capture: bool = True, + env: Optional[dict] = None, +) -> subprocess.CompletedProcess: + return subprocess.run( + cmd, + check=check, + capture_output=capture, + text=True, + env=env, + encoding="utf-8", + errors="replace", + ) + + +def print_run(cmd: list[str], *, env: Optional[dict] = None) -> None: + print(f"[RUN] {' '.join(str(x) for x in cmd)}") + subprocess.run(cmd, check=True, env=env) + + +def run_quiet(cmd: list[str], *, env: Optional[dict] = None) -> str: + try: + cp = subprocess.run( + cmd, + capture_output=True, + text=True, + env=env, + check=False, + encoding="utf-8", + errors="replace", + ) + out = (cp.stdout or cp.stderr or "").strip() + return out[:4000] + except Exception as e: + return f"" + + +def which(name: str) -> Optional[str]: + return shutil.which(name) + + +def ensure_dir(path: Path) -> None: + path.mkdir(parents=True, exist_ok=True) + + +def write_text(path: Path, text: str) -> None: + ensure_dir(path.parent) + path.write_text(text, encoding="utf-8", newline="\n") + + +def read_text(path: Path) -> str: + return path.read_text(encoding="utf-8-sig") + + +def load_json(path: Path) -> dict: + if not path.exists(): + return {} + try: + return json.loads(read_text(path)) + except Exception: + return {} + + +def current_platform_guess() -> str: + sysname = platform.system().lower() + machine = platform.machine().lower() + if sysname == "windows": + return "win-arm64" if machine in {"arm64", "aarch64"} else "win-64" + if sysname == "linux": + return "linux-aarch64" if machine in {"arm64", "aarch64"} else "linux-64" + if sysname == "darwin": + return "osx-arm64" if machine in {"arm64", "aarch64"} else "osx-64" + return f"{sysname}-{machine}" + + +def conda_explicit_filename(lock_dir: Path, platform_tag: str) -> Path: + return lock_dir / f"conda-explicit-{platform_tag}.txt" + + +def pip_lock_filename(lock_dir: Path) -> Path: + return lock_dir / "pip-freeze-all.txt" + + +def replay_pip_filename(lock_dir: Path) -> Path: + return lock_dir / "pip-freeze-replay.txt" + + +def build_plan_filename(lock_dir: Path) -> Path: + return lock_dir / "build-plan.json" + + +def meta_filename(lock_dir: Path) -> Path: + return lock_dir / "lock-meta.json" + + +def numpy_audit_filename(lock_dir: Path) -> Path: + return lock_dir / "numpy-compat-audit.txt" + + +def nerfstudio_methods_filename(lock_dir: Path) -> Path: + return lock_dir / "nerfstudio-methods-protected.json" + + +def nerfstudio_core_overrides_filename(lock_dir: Path) -> Path: + return lock_dir / "nerfstudio-core-overrides.json" + + +def msvc_log_filename(lock_dir: Path) -> Path: + return lock_dir / "msvc-toolsets.txt" + + +def msvc_selected_filename(lock_dir: Path) -> Path: + return lock_dir / "msvc-selected.txt" + + +def installer_selection_filename(lock_dir: Path) -> Path: + return lock_dir / "installer-selection.json" + + +def load_build_plan(lock_dir: Path) -> dict: + return load_json(build_plan_filename(lock_dir)) + + +def load_installer_selection(lock_dir: Path) -> dict: + return load_json(installer_selection_filename(lock_dir)) + + +def write_msvc_selected_log(lock_dir: Path, text: str) -> None: + write_text(msvc_selected_filename(lock_dir), text.rstrip() + "\n") + + +def normalize_lines(text: str, *, kind: str) -> list[str]: + out: list[str] = [] + for raw in text.replace("\r\n", "\n").replace("\r", "\n").split("\n"): + line = raw.strip() + if not line or line.startswith("#"): + continue + if kind == "pip" and (line.startswith("-e ") or line.startswith("--editable")): + continue + out.append(line) + return out + + +def normalize_pkg_line(line: str) -> str: + line = line.strip() + if PYWIN32_BAD_RE.match(line): + return "pywin32==305" + return line + + +def parse_name(line: str) -> str: + if " @ " in line: + return line.split(" @ ", 1)[0].strip().lower().replace("_", "-") + for sep in ("==", "<=", ">=", "~=", "<", ">"): + if sep in line: + return line.split(sep, 1)[0].strip().lower().replace("_", "-") + return line.strip().lower().replace("_", "-") + + +def torch_pyg_tag(torch_line: str) -> str: + return torch_line.replace("==", "-") + + +def is_protected_method_name(name: str) -> bool: + return (name or "").strip().lower().replace("_", "-") in NERFSTUDIO_METHODS_PROTECTED_NAMES + + +def is_core_override_name(name: str) -> bool: + return (name or "").strip().lower().replace("_", "-") in NERFSTUDIO_CORE_OVERRIDE_NAMES + + +def detect_tcnn_runtime() -> bool: + try: + cp = run([sys.executable, "-c", "import tinycudann as tcnn; print('OK')"], check=False) + return cp.returncode == 0 + except Exception: + return False + + +def normalized_current_pip_lines() -> list[str]: + try: + cp = run([sys.executable, "-m", "pip", "freeze", "--all"]) + except subprocess.CalledProcessError: + cp = run([sys.executable, "-m", "pip", "freeze"]) + return [normalize_pkg_line(x) for x in normalize_lines(cp.stdout, kind="pip")] + +def installed_pip_map() -> dict[str, str]: + return {parse_name(x): normalize_pkg_line(x) for x in normalized_current_pip_lines()} + +def installed_direct_url_map() -> dict[str, str]: + cp = subprocess.run( + [sys.executable, "-m", "pip", "freeze", "--all"], + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + check=False, + ) + out: dict[str, str] = {} + for raw in normalize_lines(cp.stdout, kind="pip"): + line = normalize_pkg_line(raw) + if " @ " not in line: + continue + name = parse_name(line) + out[name] = line + return out + + +def git_requirement_matches(installed_line: str, expected_git: str) -> bool: + a = (installed_line or "").strip().lower() + b = (expected_git or "").strip().lower() + return bool(a) and bool(b) and b in a + +def spec_is_exact_pin(spec: str) -> bool: + line = normalize_pkg_line(spec) + return "==" in line and " @ " not in line and not line.startswith(("-", "--")) + + +def filter_already_installed_exact_specs(lines: list[str]) -> tuple[list[str], list[str]]: + installed = installed_pip_map() + pending: list[str] = [] + skipped: list[str] = [] + for raw in lines: + line = normalize_pkg_line(raw) + if spec_is_exact_pin(line): + name = parse_name(line) + if installed.get(name, "") == line: + skipped.append(line) + continue + pending.append(line) + return pending, skipped + + + +def find_conda_lock(lock_dir: Path) -> Optional[Path]: + matches = sorted(lock_dir.glob("conda-explicit-*.txt")) + if matches: + platform_tag = current_platform_guess() + platform_match = lock_dir / f"conda-explicit-{platform_tag}.txt" + if platform_match.exists(): + return platform_match + return matches[0] + fallback = lock_dir / "conda-explicit.txt" + return fallback if fallback.exists() else None + + +def parse_platform_from_explicit(explicit_text: str) -> str: + for line in explicit_text.splitlines(): + m = re.match(r"\s*#\s*platform:\s*(\S+)", line) + if m: + return m.group(1) + return current_platform_guess() + + + +def _looks_like_windows_path(value: str) -> bool: + v = (value or "").strip() + return bool(re.match(r"^[A-Za-z]:\\", v) or re.match(r"^\\\\", v)) + + +def _strip_wrapping_quotes(value: str) -> str: + v = (value or "").strip() + while len(v) >= 2 and ((v[0] == '"' and v[-1] == '"') or (v[0] == "'" and v[-1] == "'")): + v = v[1:-1].strip() + return v + + +def sanitize_windows_path(value: str) -> str: + v = (value or "").strip() + if not v: + return "" + + # normalize slash style first, but do not aggressively collapse all backslashes + v = v.replace("/", "\\") + v = v.replace('\"', '"').replace("\'", "'") + v = _strip_wrapping_quotes(v) + + # repair malformed values like: + # C:\"C:\Program Files\... + # C:\"C:\PROGRA~1\... + # C:"C:\Program Files\... + m = re.match(r'^[A-Za-z]:(?:\\?["\']+)([A-Za-z]:\\.*)$', v) + if m: + v = m.group(1).strip() + + # remove leading/trailing stray quotes around an actual drive path + if len(v) >= 2 and v[0] == '"' and _looks_like_windows_path(v[1:]): + v = v[1:] + if len(v) >= 2 and v[-1] == '"' and _looks_like_windows_path(v[:-1]): + v = v[:-1] + + v = v.strip().strip('"').strip("'").strip() + + # collapse accidental doubled backslashes after drive/share prefix normalization + if _looks_like_windows_path(v): + drive_m = re.match(r'^([A-Za-z]:\\)(.*)$', v) + unc_m = re.match(r'^(\\\\[^\\]+\\[^\\]+\\?)(.*)$', v) + if drive_m: + prefix, rest = drive_m.groups() + rest = re.sub(r'\\+', r'\\', rest) + v = prefix + rest + elif unc_m: + prefix, rest = unc_m.groups() + rest = re.sub(r'\\+', r'\\', rest) + v = prefix + rest + + # keep directory paths as directories, but trim file-path trailing separators + if re.search(r'\.(exe|bat|cmd)$', v, re.I): + v = v.rstrip("\\/") + + return os.path.normpath(v) if v else "" + + +def to_short_path(path_value: str) -> str: + path_value = sanitize_windows_path(path_value) + if not path_value: + return "" + + if platform.system().lower() != "windows": + return path_value + + # Prefer the clean normalized long path. Use 8.3 only as a fallback. + try: + if Path(path_value).exists(): + return os.path.normpath(path_value) + except Exception: + pass + + try: + cp = subprocess.run( + ["cmd", "/d", "/s", "/c", f'for %I in ("{path_value}") do @echo %~sI'], + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + check=False, + ) + out = sanitize_windows_path((cp.stdout or "").strip()) + if cp.returncode == 0 and out and _looks_like_windows_path(out): + return os.path.normpath(out) + except Exception: + pass + + return os.path.normpath(path_value) + + +def normalize_windows_path_list(value: str) -> str: + if platform.system().lower() != "windows": + return value or "" + + parts: list[str] = [] + seen: set[str] = set() + + for raw in (value or "").split(os.pathsep): + item = sanitize_windows_path(raw) + if not item: + continue + key = os.path.normcase(os.path.normpath(item)) + if key in seen: + continue + seen.add(key) + parts.append(os.path.normpath(item)) + + return os.pathsep.join(parts) +def short_toolset_version(version: str) -> str: + version = (version or "").strip() + if not version: + return "" + parts = version.split(".") + if len(parts) >= 2: + return f"{parts[0]}.{parts[1]}" + return version + + +def normalize_selected_toolset(selected: dict | None) -> dict | None: + if not selected: + return None + out = dict(selected) + full = (out.get("toolset_full") or out.get("toolset") or "").strip() + out["toolset_full"] = full + out["toolset_short"] = short_toolset_version(full) + out["toolset"] = full + return out + + +def vswhere_path() -> Optional[str]: + candidates = [ + os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", "Installer", "vswhere.exe"), + os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", "Installer", "vswhere.exe"), + ] + for c in candidates: + if c and os.path.exists(c): + return c + return None + + +def list_msvc_toolsets() -> list[dict]: + if platform.system().lower() != "windows": + return [] + out: list[dict] = [] + seen: set[tuple[str, str]] = set() + installs: list[Path] = [] + vswhere = vswhere_path() + if vswhere: + cp = run( + [ + vswhere, + "-products", + "*", + "-requires", + "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", + "installationPath", + ], + check=False, + ) + for line in cp.stdout.splitlines(): + line = line.strip() + if line: + installs.append(Path(line)) + for root in installs: + msvc_root = root / "VC" / "Tools" / "MSVC" + if not msvc_root.exists(): + continue + for d in sorted(msvc_root.iterdir()): + if not d.is_dir(): + continue + vcvarsall = root / "VC" / "Auxiliary" / "Build" / "vcvarsall.bat" + cl = d / "bin" / "Hostx64" / "x64" / "cl.exe" + if not (vcvarsall.exists() and cl.exists()): + continue + key = (str(root), d.name) + if key in seen: + continue + seen.add(key) + normalized = normalize_selected_toolset( + { + "installation": _norm_win_path(str(root)), + "toolset": d.name, + "vcvarsall": _norm_win_path(str(vcvarsall)), + "cl": _norm_win_path(str(cl)), + } + ) + if normalized: + out.append(normalized) + out.sort(key=lambda x: x["toolset_full"], reverse=True) + return out + +def ensure_build_tooling_for_cpp(lock_dir: Path, msvc_mode: str) -> None: + print("[INFO] Repairing Python build tooling required by native extensions...") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "pip", + "setuptools==75.1.0", + "wheel==0.44.0", + "Cython", + "pkgconfig", + "pybind11", + ], + msvc_mode, + ) + +def write_msvc_log(lock_dir: Path) -> list[dict]: + toolsets = list_msvc_toolsets() + lines: list[str] = [] + if not toolsets: + lines.append("No MSVC toolsets detected.") + else: + lines.append("Detected MSVC toolsets:") + for t in toolsets: + lines.append( + f"{t['toolset_full']} | short={t['toolset_short']} | " + f"install={t['installation']} | cl={t['cl']} | vcvarsall={t['vcvarsall']}" + ) + write_text(msvc_log_filename(lock_dir), "\n".join(lines) + "\n") + return toolsets + + +def choose_msvc_toolset(lock_dir: Path, requested: str) -> Optional[dict]: + toolsets = write_msvc_log(lock_dir) + requested = (requested or "").strip().lower() + if not toolsets or requested in {"", "system"}: + return None + if requested == "auto": + for t in toolsets: + if t["toolset_short"] == "14.38" or t["toolset_full"].startswith("14.38"): + return t + return toolsets[0] + if requested == "14": + for t in toolsets: + if t["toolset_full"].startswith("14."): + return t + return None + for t in toolsets: + if t["toolset_short"] == requested or t["toolset_full"].startswith(requested): + return t + return None + + +def detect_cuda_root() -> str: + candidates = [ + os.environ.get("CUDA_PATH", ""), + os.environ.get("CUDA_HOME", ""), + ] + for cand in candidates: + cand = (cand or "").strip().strip('"') + if cand and Path(cand).exists(): + return cand + nvcc = shutil.which("nvcc.exe") or shutil.which("nvcc") + if nvcc: + try: + return str(Path(nvcc).resolve().parent.parent) + except Exception: + pass + default_cuda = Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA GPU Computing Toolkit" / "CUDA" / "v11.8" + if default_cuda.exists(): + return str(default_cuda) + return "" + + +def detect_git_dirs() -> list[str]: + candidates: list[str] = [] + seen: set[str] = set() + + git_exe = shutil.which("git.exe") or shutil.which("git") + if git_exe: + gp = os.path.normpath(str(Path(git_exe).resolve().parent)) + key = os.path.normcase(gp) + if key not in seen: + seen.add(key) + candidates.append(gp) + + program_files = os.environ.get("ProgramFiles", r"C:\Program Files") + for p in ( + Path(program_files) / "Git" / "cmd", + Path(program_files) / "Git" / "bin", + ): + if p.exists(): + gp = os.path.normpath(str(p)) + key = os.path.normcase(gp) + if key not in seen: + seen.add(key) + candidates.append(gp) + + return candidates + + +def get_runtime_path_entries() -> list[str]: + entries: list[str] = [] + + conda_prefix = os.environ.get("CONDA_PREFIX", "") + if conda_prefix: + prefix = Path(conda_prefix) + for p in ( + prefix / "Scripts", + prefix, + prefix / "Library" / "bin", + prefix / "Library" / "usr" / "bin", + prefix / "bin", + ): + entries.append(str(p)) + + entries.append(str(Path(sys.executable).resolve().parent)) + entries.extend(detect_git_dirs()) + + return entries + +def _norm_win_path(value: str) -> str: + clean = sanitize_windows_path(value) + if not clean: + return "" + return os.path.normpath(clean) + +def _norm_win_list(values: list[str]) -> list[str]: + out: list[str] = [] + seen: set[str] = set() + + for v in values: + nv = _norm_win_path(v) + if not nv: + continue + key = nv.lower() + if key in seen: + continue + seen.add(key) + out.append(nv) + + return out + +def parse_set_output_to_env(text: str) -> dict[str, str]: + parsed_env: dict[str, str] = {} + + path_list_keys = {"PATH", "INCLUDE", "LIB", "LIBPATH"} + path_scalar_keys = { + "CC", + "CXX", + "CUDAHOSTCXX", + "CLCACHE_CL", + "CMAKE_CUDA_HOST_COMPILER", + "VCToolsInstallDir", + "VCINSTALLDIR", + "VSINSTALLDIR", + "CUDA_PATH", + "CUDA_HOME", + "CUDAToolkit_ROOT", + } + + for line in (text or "").splitlines(): + if "=" not in line: + continue + + k, v = line.split("=", 1) + k = k.strip() + if not k: + continue + + ku = k.upper() + + if ku in path_list_keys: + parsed_env[k] = normalize_windows_path_list(v) + elif ku in path_scalar_keys: + parsed_env[k] = _norm_win_path(v) + else: + parsed_env[k] = v.strip().replace('\\"', '"').replace('""', '"') + + return parsed_env + +def build_bootstrap_context(lock_dir: Path, requested: str) -> dict: + requested = (requested or "").strip() + installer = load_installer_selection(lock_dir) + + effective = str( + installer.get("preferred_msvc") + or requested + or os.environ.get("PREFERRED_MSVC") + or "" + ).strip() + + selected = None + cuda_root = "" + git_dirs: list[str] = [] + runtime_entries: list[str] = [] + + if platform.system().lower() == "windows": + selected = choose_msvc_toolset(lock_dir, effective) + selected = normalize_selected_toolset(selected) + + if selected: + selected = { + **selected, + "installation": _norm_win_path(selected.get("installation", "")), + "vcvarsall": _norm_win_path(selected.get("vcvarsall", "")), + "cl": _norm_win_path(selected.get("cl", "")), + } + + cuda_root = _norm_win_path(detect_cuda_root()) + git_dirs = _norm_win_list(detect_git_dirs()) + runtime_entries = _norm_win_list(get_runtime_path_entries()) + + ctx = { + "requested": effective, + "selected": selected, + "cuda_root": cuda_root, + "git_dirs": git_dirs, + "runtime_path_entries": runtime_entries, + } + + lines = [ + f"requested={effective or 'system'}", + f"cuda_root={cuda_root}", + f"git_dirs={';'.join(git_dirs)}", + f"runtime_path_entries={';'.join(runtime_entries)}", + ] + + if selected: + lines.extend( + [ + f"selected_toolset={selected['toolset_full']}", + f"selected_short={selected['toolset_short']}", + f"selected_install={selected['installation']}", + f"selected_cl={selected['cl']}", + f"selected_vcvarsall={selected['vcvarsall']}", + "mode=subprocess-shell-bootstrap", + ] + ) + else: + lines.append("mode=system/no-forced-toolset") + + write_msvc_selected_log(lock_dir, "\n".join(lines) + "\n") + return ctx + +def find_header_in_include(include_value: str, header_name: str) -> str: + header_name = (header_name or "").strip() + if not header_name: + return "" + + for raw in normalize_windows_path_list(include_value).split(os.pathsep): + root = _norm_win_path(raw) + if not root: + continue + try: + p = Path(root) / header_name + if p.exists(): + return str(p) + except Exception: + continue + + return "" + +def validate_msvc_from_shell(lock_dir: Path, ctx: dict) -> tuple[bool, list[str]]: + if platform.system().lower() != "windows": + return True, [] + + selected = ctx.get("selected") + if not selected: + return True, [] + + vcvarsall = _norm_win_path(selected.get("vcvarsall", "")) + cl = _norm_win_path(selected.get("cl", "")) + + errors: list[str] = [] + + if not vcvarsall or not Path(vcvarsall).exists(): + errors.append(f"vcvarsall missing: {vcvarsall}") + + if not cl or not Path(cl).exists(): + errors.append(f"cl.exe missing: {cl}") + + return len(errors) == 0, errors + + +def _cmdline_from_args(args: list[str]) -> str: + return subprocess.list2cmdline([str(x) for x in args]) + + +def _make_bootstrap_batch( + lock_dir: Path, + command: list[str], + msvc_mode: str, + extra_env: Optional[dict] = None, +) -> str: + ctx = build_bootstrap_context(lock_dir, msvc_mode) + ok, errors = validate_msvc_from_shell(lock_dir, ctx) + if not ok: + raise RuntimeError("MSVC bootstrap metadata invalid: " + "; ".join(errors)) + + selected = ctx.get("selected") + cuda_root = ctx.get("cuda_root", "") + runtime_entries = list(ctx.get("runtime_path_entries", [])) + extra_env = extra_env or {} + + lines: list[str] = [ + "@echo off", + "setlocal EnableExtensions", + ] + + if platform.system().lower() == "windows" and selected: + vcvarsall = _norm_win_path(selected["vcvarsall"]) + short_ver = selected["toolset_short"] + full_ver = selected["toolset_full"] + cl = _norm_win_path(selected["cl"]) + cl_dir = _norm_win_path(str(Path(cl).parent)) + + lines.extend( + [ + f'call "{vcvarsall}" x64 -vcvars_ver={short_ver}', + f'if errorlevel 1 call "{vcvarsall}" x64 -vcvars_ver={full_ver}', + f'if errorlevel 1 call "{vcvarsall}" x64', + "if errorlevel 1 exit /b %errorlevel%", + f'set "NS_SELECTED_MSVC_TOOLSET={full_ver}"', + f'set "NS_SELECTED_MSVC_CL={cl}"', + f'set "CC={cl}"', + f'set "CXX={cl}"', + f'set "CUDAHOSTCXX={cl}"', + f'set "CLCACHE_CL={cl}"', + f'set "CMAKE_CUDA_HOST_COMPILER={cl}"', + f'set "CMAKE_GENERATOR_TOOLSET=v143,version={full_ver}"', + 'set "DISTUTILS_USE_SDK=1"', + 'set "MSSdk=1"', + ] + ) + + if cuda_root: + cuda_root = _norm_win_path(cuda_root) + cuda_bin = _norm_win_path(str(Path(cuda_root) / "bin")) + + lines.extend( + [ + f'set "CUDA_PATH={cuda_root}"', + f'set "CUDA_HOME={cuda_root}"', + f'set "CUDAToolkit_ROOT={cuda_root}"', + ] + ) + + if Path(cuda_bin).exists(): + runtime_entries.insert(0, cuda_bin) + + merged_runtime = normalize_windows_path_list(os.pathsep.join(runtime_entries)) + if merged_runtime: + lines.append(f'set "PATH={merged_runtime};%PATH%"') + + # tiny-cuda-nn / torch cpp_extension can incorrectly pivot into ROCm mode on + # Windows when ROCm-related environment variables leak into the build shell. + # Force a clean CUDA-only build context for Windows extension builds. + if platform.system().lower() == "windows": + lines.extend( + [ + 'set "ROCM_HOME="', + 'set "ROCM_PATH="', + 'set "HIP_HOME="', + 'set "HIP_PATH="', + 'set "HCC_HOME="', + 'set "HIP_PATH_57="', + 'set "HIP_DEVICE_LIB_PATH="', + 'set "PYTORCH_ROCM_ARCH="', + ] + ) + + for k, v in extra_env.items(): + if v is None: + continue + sval = str(v) + if sval == "": + lines.append(f'set "{k}="') + continue + lines.append(f'set "{k}={sval.strip()}"') + + lines.append(_cmdline_from_args(command)) + lines.append("exit /b %errorlevel%") + return "\n".join(lines) + "\n" + + +def run_bootstrapped( + lock_dir: Path, + command: list[str], + msvc_mode: str, + *, + check: bool = True, + extra_env: Optional[dict] = None, +) -> subprocess.CompletedProcess: + if platform.system().lower() != "windows": + return subprocess.run(command, check=check, capture_output=False, text=True) + + script = _make_bootstrap_batch(lock_dir, command, msvc_mode, extra_env=extra_env) + with tempfile.NamedTemporaryFile("w", suffix=".cmd", delete=False, encoding="utf-8", newline="\r\n") as f: + f.write(script) + temp_cmd = f.name + + try: + # Pass the temporary batch path as a raw argv element. Adding manual quotes here + # causes cmd.exe to receive an extra-quoted command like + # ""C:\path\tmp.cmd"", which then fails with + # "not recognized as an internal or external command". + return subprocess.run(["cmd", "/d", "/s", "/c", temp_cmd], check=check) + finally: + try: + os.unlink(temp_cmd) + except OSError: + pass + + +def print_run_bootstrapped( + lock_dir: Path, + command: list[str], + msvc_mode: str, + *, + extra_env: Optional[dict] = None, +) -> None: + print(f"[RUN] {' '.join(str(x) for x in command)}") + run_bootstrapped(lock_dir, command, msvc_mode, check=True, extra_env=extra_env) + + +def detect_torch_lines(lines: list[str]) -> list[str]: + found = [normalize_pkg_line(line) for line in lines if TORCH_LINE_RE.match(line)] + if not found: + return DEFAULT_TORCH[:] + uniq: list[str] = [] + for line in found: + if line not in uniq: + uniq.append(line) + return uniq + + +def detect_pyg_lines(lines: list[str]) -> list[str]: + uniq: list[str] = [] + for line in lines: + line = normalize_pkg_line(line) + if PYG_LINE_RE.match(line) and line not in uniq: + uniq.append(line) + return uniq + + +def detect_numpy_baseline(lines: list[str]) -> str: + for line in lines: + if line.lower().startswith("numpy=="): + version = line.split("==", 1)[1].strip() + if version and not version.startswith("2"): + return f"numpy=={version}" + return DEFAULT_NUMPY + + +def detect_tcnn_line(lines: list[str]) -> str: + for line in lines: + if TCNN_REQ_RE.match(line): + return normalize_pkg_line(line) + return TCNN_GIT + + +def current_tcnn_arch() -> str: + return os.environ.get("TCNN_CUDA_ARCHITECTURES", "").strip() + + +def torch_cuda_arch_list_value(value: str) -> str: + value = (value or "").strip() + if not value: + return "" + m = re.fullmatch(r"(\d)(\d)(?:\+PTX)?", value, re.I) + if m: + major, minor = m.group(1), m.group(2) + suffix = "+PTX" if value.upper().endswith("+PTX") else "" + return f"{major}.{minor}{suffix}" + return value + + +def compute_replay_lines(lines: list[str]) -> list[str]: + replay: list[str] = [] + for raw in lines: + line = normalize_pkg_line(raw) + name = parse_name(line) + if is_protected_method_name(name) or is_core_override_name(name): + continue + if any(p.search(line) for p in SKIP_PATTERNS): + continue + if any(p.search(line) for p in DEFER_PATTERNS): + continue + replay.append(line) + return replay + + + + + +def export_nerfstudio_methods(lock_dir: Path, lines: list[str]) -> None: + installed: dict[str, dict] = {} + for raw in lines: + line = normalize_pkg_line(raw) + name = parse_name(line) + if not is_protected_method_name(name): + continue + for key, spec in NERFSTUDIO_METHODS_PROTECTED.items(): + if name in spec["pip_names"]: + installed[key] = { + "locked_requirement": line, + "install_ref": spec["install_ref"], + "patch_rel": spec["patch_rel"], + "pip_names": sorted(spec["pip_names"]), + "category": spec.get("category", "method"), + } + break + + payload = { + "protected_methods": { + key: { + "install_ref": spec["install_ref"], + "patch_rel": spec["patch_rel"], + "pip_names": sorted(spec["pip_names"]), + "category": spec.get("category", "method"), + "locked_requirement": installed.get(key, {}).get("locked_requirement", ""), + "present_in_lock": key in installed, + } + for key, spec in NERFSTUDIO_METHODS_PROTECTED.items() + } + } + write_text(nerfstudio_methods_filename(lock_dir), json.dumps(payload, indent=2) + "\n") + + +def export_nerfstudio_core_overrides(lock_dir: Path, lines: list[str]) -> None: + installed: dict[str, dict] = {} + for raw in lines: + line = normalize_pkg_line(raw) + name = parse_name(line) + if not is_core_override_name(name): + continue + for key, spec in NERFSTUDIO_CORE_OVERRIDES.items(): + if name in spec["pip_names"]: + installed[key] = { + "locked_requirement": line, + "install_ref": spec["install_ref"], + "patch_rel": spec["patch_rel"], + "pip_names": sorted(spec["pip_names"]), + "category": spec.get("category", "core_dependency"), + "enforce_as_standard": bool(spec.get("enforce_as_standard", False)), + } + break + + payload = { + "core_overrides": { + key: { + "install_ref": spec["install_ref"], + "patch_rel": spec["patch_rel"], + "pip_names": sorted(spec["pip_names"]), + "category": spec.get("category", "core_dependency"), + "enforce_as_standard": bool(spec.get("enforce_as_standard", False)), + "locked_requirement": installed.get(key, {}).get("locked_requirement", ""), + "present_in_lock": key in installed, + } + for key, spec in NERFSTUDIO_CORE_OVERRIDES.items() + } + } + write_text(nerfstudio_core_overrides_filename(lock_dir), json.dumps(payload, indent=2) + "\n") + +def export_numpy_audit(lock_dir: Path, lines: list[str], plan: dict) -> None: + rows = [] + for line in lines: + name = parse_name(line) + if name.startswith("numpy") or name in {"torch", "torchvision", "torchaudio", "opencv-python", "opencv-contrib-python", "matplotlib", "scipy", "pandas", "pycolmap", "open3d", "tensorflow"}: + rows.append(line) + rows.extend([f"PLAN torch_preinstall: {x}" for x in plan.get("torch_preinstall", [])]) + rows.extend([f"PLAN pyg_wheels: {x}" for x in plan.get("pyg_wheels", [])]) + rows.extend([f"PLAN deferred: {x}" for x in plan.get("deferred", [])]) + write_text(numpy_audit_filename(lock_dir), "\n".join(dict.fromkeys(rows)) + "\n") + + +def export_locks(lock_dir: Path, conda_exe: Optional[str] = None, msvc_mode: str = "") -> int: + ensure_dir(lock_dir) + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + platform_tag = current_platform_guess() + conda_lock_path: Optional[Path] = None + + print(f"[DEBUG] export_locks using conda executable: {conda_exe}") + print(f"[DEBUG] export_locks CONDA_PREFIX={os.environ.get('CONDA_PREFIX')}") + + if conda_exe and os.environ.get("CONDA_PREFIX"): + cp = run([conda_exe, "list", "--explicit", "--md5"]) + explicit = cp.stdout + platform_tag = parse_platform_from_explicit(explicit) + conda_lock_path = conda_explicit_filename(lock_dir, platform_tag) + write_text(conda_lock_path, explicit) + cp_json = run([conda_exe, "list", "--json"]) + write_text(lock_dir / "conda-list.json", cp_json.stdout) + else: + print("[WARN] Active conda environment not detected; skipping conda explicit export.") + + pip_lines = normalized_current_pip_lines() + write_text(pip_lock_filename(lock_dir), "\n".join(pip_lines) + "\n") + write_text(replay_pip_filename(lock_dir), "\n".join(compute_replay_lines(pip_lines)) + "\n") + + installer = load_installer_selection(lock_dir) + effective_msvc = str(installer.get("preferred_msvc") or msvc_mode or os.environ.get("PREFERRED_MSVC") or "").strip() + ctx = build_bootstrap_context(lock_dir, effective_msvc) + + numpy_baseline = detect_numpy_baseline(pip_lines) + build_plan = { + "numpy_stable": numpy_baseline, + "torch_preinstall": detect_torch_lines(pip_lines), + "torch_index": TORCH_INDEX, + "pyg_wheels": detect_pyg_lines(pip_lines), + "pyg_index_template": PYG_INDEX_TEMPLATE, + "tinycudann": { + "requirement": detect_tcnn_line(pip_lines), + "cuda_arch": str(installer.get("cuda_arch") or current_tcnn_arch() or "").strip(), + }, + "pycolmap": { + "requirement": PYCOLMAP_GIT, + }, + "deferred": [x for x in pip_lines if any(p.search(x) for p in DEFER_PATTERNS)], + "nerfstudio_methods_protected": { + key: { + "pip_names": sorted(value["pip_names"]), + "install_ref": value["install_ref"], + "patch_rel": value["patch_rel"], + "category": value.get("category", "method"), + } + for key, value in NERFSTUDIO_METHODS_PROTECTED.items() + }, + "nerfstudio_core_overrides": { + key: { + "pip_names": sorted(value["pip_names"]), + "install_ref": value["install_ref"], + "patch_rel": value["patch_rel"], + "category": value.get("category", "core_dependency"), + "enforce_as_standard": bool(value.get("enforce_as_standard", False)), + } + for key, value in NERFSTUDIO_CORE_OVERRIDES.items() + }, + "skipped_from_bulk": [ + x for x in pip_lines + if any(p.search(x) for p in SKIP_PATTERNS) + or is_protected_method_name(parse_name(x)) + or is_core_override_name(parse_name(x)) + ], + "build_tooling": BUILD_TOOL_PKGS, + "preferred_msvc": effective_msvc, + "bootstrap_mode": "subprocess-shell-bootstrap", + "selected_toolset": (ctx.get("selected") or {}).get("toolset_full", ""), + "selected_installation": (ctx.get("selected") or {}).get("installation", ""), + "cuda_root": ctx.get("cuda_root", ""), + } + write_text(build_plan_filename(lock_dir), json.dumps(build_plan, indent=2) + "\n") + export_numpy_audit(lock_dir, pip_lines, build_plan) + export_nerfstudio_methods(lock_dir, pip_lines) + export_nerfstudio_core_overrides(lock_dir, pip_lines) + write_msvc_log(lock_dir) + + meta = { + "created_utc": datetime.now(timezone.utc).isoformat(), + "python_executable": sys.executable, + "python_version": sys.version, + "platform_guess": platform_tag, + "conda_executable": conda_exe, + "conda_env": os.environ.get("CONDA_DEFAULT_ENV"), + "conda_prefix": os.environ.get("CONDA_PREFIX"), + "conda_lock": conda_lock_path.name if conda_lock_path else None, + "pip_lock": pip_lock_filename(lock_dir).name, + "pip_replay": replay_pip_filename(lock_dir).name, + "build_plan": build_plan_filename(lock_dir).name, + "numpy_audit": numpy_audit_filename(lock_dir).name, + "nerfstudio_methods_protected": nerfstudio_methods_filename(lock_dir).name, + "nerfstudio_core_overrides": nerfstudio_core_overrides_filename(lock_dir).name, + "msvc_log": msvc_log_filename(lock_dir).name, + "msvc_selected_log": msvc_selected_filename(lock_dir).name, + "installer_selection": installer_selection_filename(lock_dir).name if installer else None, + } + write_text(meta_filename(lock_dir), json.dumps(meta, indent=2) + "\n") + + print(f"[OK] Wrote pip lock: {pip_lock_filename(lock_dir)}") + print(f"[OK] Wrote replay-safe pip lock: {replay_pip_filename(lock_dir)}") + if conda_lock_path: + print(f"[OK] Wrote conda lock: {conda_lock_path}") + print(f"[OK] Wrote build plan: {build_plan_filename(lock_dir)}") + print(f"[OK] Wrote metadata: {meta_filename(lock_dir)}") + print(f"[OK] Wrote NumPy audit: {numpy_audit_filename(lock_dir)}") + print(f"[OK] Wrote protected Nerfstudio methods manifest: {nerfstudio_methods_filename(lock_dir)}") + print(f"[OK] Wrote Nerfstudio core overrides manifest: {nerfstudio_core_overrides_filename(lock_dir)}") + print(f"[OK] Wrote MSVC toolset log: {msvc_log_filename(lock_dir)}") + print(f"[OK] Wrote MSVC selected log: {msvc_selected_filename(lock_dir)}") + return 0 + + +def diff_summary(expected: list[str], current: list[str], label: str) -> tuple[bool, str]: + if expected == current: + return True, f"[OK] {label} matches lock exactly." + expected_set = set(expected) + current_set = set(current) + missing = sorted(expected_set - current_set) + extra = sorted(current_set - expected_set) + lines = [f"[FAIL] {label} differs from lock."] + if missing: + lines.append(" Missing/changed (first 10):") + lines.extend([f" - {x}" for x in missing[:10]]) + if extra: + lines.append(" Extra/different (first 10):") + lines.extend([f" + {x}" for x in extra[:10]]) + return False, "\n".join(lines) + + +def check_locks(lock_dir: Path, conda_exe: Optional[str] = None) -> int: + ok = True + conda_lock = find_conda_lock(lock_dir) + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + print(f"[DEBUG] check_locks using conda executable: {conda_exe}") + print(f"[DEBUG] check_locks CONDA_PREFIX={os.environ.get('CONDA_PREFIX')}") + if conda_lock and conda_exe and os.environ.get("CONDA_PREFIX"): + current = run([conda_exe, "list", "--explicit", "--md5"]).stdout + good, msg = diff_summary( + normalize_lines(read_text(conda_lock), kind="conda"), + normalize_lines(current, kind="conda"), + "Conda explicit lock", + ) + print(msg) + ok &= good + elif conda_lock: + print("[WARN] Conda lock exists but current shell is not an active conda env; skipping conda check.") + else: + print("[WARN] No conda lock found.") + + pip_lock = pip_lock_filename(lock_dir) + if pip_lock.exists(): + current = normalized_current_pip_lines() + good, msg = diff_summary( + [normalize_pkg_line(x) for x in normalize_lines(read_text(pip_lock), kind="pip")], + current, + "pip freeze lock", + ) + print(msg) + ok &= good + else: + print("[WARN] No pip lock found.") + return 0 if ok else 2 + + +def get_installed_version(pkg_name: str) -> str: + cp = subprocess.run( + [sys.executable, "-m", "pip", "show", pkg_name], + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + ) + if cp.returncode != 0: + return "" + for line in cp.stdout.splitlines(): + if line.lower().startswith("version:"): + return line.split(":", 1)[1].strip() + return "" + + +def install_packaging_base(lock_dir: Path, msvc_mode: str) -> None: + print("[INFO] Installing build/runtime base tooling...") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + *BUILD_TOOL_PKGS, + ], + msvc_mode, + ) + + +def ensure_numpy_stable(lock_dir: Path, msvc_mode: str, numpy_spec: str, state: dict, *, reason: str) -> None: + desired = numpy_spec.split("==", 1)[1] if "==" in numpy_spec else "" + current = get_installed_version("numpy") + if state.get("numpy_version") == desired and current == desired: + print(f"[INFO] NumPy already stable at {desired}; skipping reinstall ({reason}).") + return + print(f"[INFO] Enforcing stable NumPy policy: {numpy_spec} ({reason})") + print_run_bootstrapped( + lock_dir, + [sys.executable, "-m", "pip", "install", *PIP_VERBOSE_ARGS, "--upgrade", "--force-reinstall", numpy_spec], + msvc_mode, + ) + state["numpy_version"] = desired or get_installed_version("numpy") + + +def install_torch_preinstall(lock_dir: Path, msvc_mode: str, torch_lines: list[str], numpy_spec: str, state: dict) -> None: + if not torch_lines: + torch_lines = DEFAULT_TORCH[:] + pending_torch, skipped_torch = filter_already_installed_exact_specs(torch_lines) + if skipped_torch: + print(f"[INFO] Skipping already-installed torch package(s): {', '.join(skipped_torch)}") + if not pending_torch: + print("[INFO] Torch stack already aligned with requested exact versions; skipping reinstall.") + state["numpy_version"] = numpy_spec.split("==", 1)[1] if "==" in numpy_spec else state.get("numpy_version", "") + return + print(f"[INFO] Installing torch stack first WITH dependencies: {', '.join(pending_torch)}") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + numpy_spec, + *pending_torch, + "--index-url", + TORCH_INDEX, + ], + msvc_mode, + ) + state["numpy_version"] = numpy_spec.split("==", 1)[1] if "==" in numpy_spec else state.get("numpy_version", "") + + +def install_pyg_wheels(lock_dir: Path, msvc_mode: str, torch_lines: list[str], pyg_lines: list[str]) -> None: + if not pyg_lines: + return + torch_line = next((x for x in torch_lines if x.lower().startswith("torch==")), DEFAULT_TORCH[0]) + index_url = PYG_INDEX_TEMPLATE.format(torch_tag=torch_pyg_tag(torch_line)) + pending_pyg, skipped_pyg = filter_already_installed_exact_specs(pyg_lines) + if skipped_pyg: + print(f"[INFO] Skipping already-installed PyG wheel(s): {', '.join(skipped_pyg)}") + for line in pending_pyg: + print(f"[INFO] Installing PyG wheel from prebuilt index: {line}") + print_run_bootstrapped( + lock_dir, + [sys.executable, "-m", "pip", "install", *PIP_VERBOSE_ARGS, line, "-f", index_url], + msvc_mode, + ) + + +def split_pip_lock(lock_text: str, lock_dir: Path) -> tuple[list[str], list[str], str, list[str], list[str], list[str]]: + lines = [normalize_pkg_line(x) for x in normalize_lines(lock_text, kind="pip")] + plan = load_build_plan(lock_dir) + torch_lines = plan.get("torch_preinstall") or detect_torch_lines(lines) + pyg_lines = plan.get("pyg_wheels") or detect_pyg_lines(lines) + tcnn_line = (plan.get("tinycudann") or {}).get("requirement") or detect_tcnn_line(lines) + torch_names = {parse_name(x) for x in torch_lines} + pyg_names = {parse_name(x) for x in pyg_lines} + bulk, deferred, av_lines = [], [], [] + for line in lines: + name = parse_name(line) + if name in torch_names or name in pyg_names or name == "numpy": + continue + if is_protected_method_name(name) or is_core_override_name(name): + continue + if name in {"tinycudann", "tiny-cuda-nn"}: + continue + if AV_LINE_RE.match(line): + av_lines.append(line) + continue + if any(p.search(line) for p in DEFER_PATTERNS): + deferred.append(line) + continue + if any(p.search(line) for p in SKIP_PATTERNS): + continue + bulk.append(line) + return torch_lines, pyg_lines, tcnn_line, bulk, deferred, av_lines + + +def install_requirements_file(lock_dir: Path, msvc_mode: str, lines: list[str], tmp_path: Path) -> None: + if not lines: + return + cleaned = [normalize_pkg_line(x) for x in lines] + pending, skipped = filter_already_installed_exact_specs(cleaned) + if skipped: + print(f"[INFO] Skipping already-installed exact requirement(s): {', '.join(skipped[:20])}" + (" ..." if len(skipped) > 20 else "")) + if not pending: + print(f"[INFO] All requested exact requirements already installed for: {tmp_path.name}") + return + write_text(tmp_path, "\n".join(pending) + "\n") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "--no-deps", + "--no-build-isolation", + "-r", + str(tmp_path), + ], + msvc_mode, + ) + + +def install_tcnn(lock_dir: Path, msvc_mode: str, tcnn_line: str, tcnn_arch: str) -> None: + if tcnn_runtime_ok(tcnn_arch): + print("[INFO] tiny-cuda-nn already importable and working; skipping rebuild.") + return + if not tcnn_line: + return + try: + import tinycudann as tcnn # noqa: F401 + print("[INFO] tinycudann already importable and runtime-usable; skipping rebuild.") + return + except Exception: + pass + ensure_build_tooling_for_cpp(lock_dir, msvc_mode) + + try: + import pkg_resources # noqa: F401 + print("[INFO] pkg_resources available.") + except Exception: + raise RuntimeError("pkg_resources is still unavailable after setuptools repair.") + + print("[INFO] Installing tiny-cuda-nn torch bindings...") + print(f"[INFO] sys.executable={sys.executable}") + + if tcnn_arch: + print(f"[INFO] TCNN_CUDA_ARCHITECTURES={tcnn_arch}") + print(f"[INFO] TORCH_CUDA_ARCH_LIST={torch_cuda_arch_list_value(tcnn_arch)}") + + ctx = build_bootstrap_context(lock_dir, msvc_mode) + selected = ctx.get("selected") + if selected: + print(f"[INFO] Using bootstrapped MSVC toolset: {selected['toolset_full']}") + print(f"[INFO] Bootstrap log: {msvc_selected_filename(lock_dir)}") + + torch_arch_list = torch_cuda_arch_list_value(tcnn_arch) + extra_env = { + "FORCE_CUDA": "1", + "TORCH_CUDA_ARCH_LIST": torch_arch_list, + "MAX_JOBS": "1", + "CMAKE_BUILD_PARALLEL_LEVEL": "1", + "DISTUTILS_USE_SDK": "1", + "MSSdk": "1", + "ROCM_HOME": "", + "ROCM_PATH": "", + "HIP_HOME": "", + "HIP_PATH": "", + "HCC_HOME": "", + "HIP_PATH_57": "", + "HIP_DEVICE_LIB_PATH": "", + "PYTORCH_ROCM_ARCH": "", + } + if tcnn_arch: + extra_env["TCNN_CUDA_ARCHITECTURES"] = tcnn_arch + + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-c", + ( + "import os,sys; " + "print('[BOOTSTRAP CHECK] python=', sys.executable); " + "print('[BOOTSTRAP CHECK] CUDA_HOME=', os.environ.get('CUDA_HOME')); " + "print('[BOOTSTRAP CHECK] CUDA_PATH=', os.environ.get('CUDA_PATH')); " + "print('[BOOTSTRAP CHECK] TCNN_CUDA_ARCHITECTURES=', os.environ.get('TCNN_CUDA_ARCHITECTURES')); " + "print('[BOOTSTRAP CHECK] TORCH_CUDA_ARCH_LIST=', os.environ.get('TORCH_CUDA_ARCH_LIST'))" + ), + ], + msvc_mode, + extra_env=extra_env, + ) + + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "--no-build-isolation", + "--no-cache-dir", + TCNN_GIT, + ], + msvc_mode, + extra_env=extra_env, + ) + +def tcnn_runtime_ok(expected_arch=""): + import tinycudann as tcnn + import torch + return torch.cuda.is_available() + + +def install_deferred(lock_dir: Path, msvc_mode: str, lines: list[str]) -> None: + leftovers = [x for x in lines if not TCNN_REQ_RE.match(x)] + if leftovers: + print(f"[INFO] Installing deferred package(s): {', '.join(leftovers)}") + install_requirements_file(lock_dir, msvc_mode, leftovers, lock_dir / ".tmp-deferred-install.txt") + + +def install_av(lock_dir: Path, msvc_mode: str, lines: list[str]) -> None: + if not lines: + return + print("[INFO] Installing AV prerequisites, then AV...") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "setuptools<81", + "wheel", + "pip", + "Cython", + "pkgconfig", + "pybind11", + "numpy<2", + ], + msvc_mode, + ) + install_requirements_file(lock_dir, msvc_mode, lines, lock_dir / ".tmp-av-install.txt") + + +def choose_conda_restore_cmd(conda_exe: str, explicit_file: Path) -> list[str]: + mamba = which("mamba") or which("mamba.exe") + micromamba = which("micromamba") or which("micromamba.exe") + if mamba: + return [mamba, "install", "--yes", "--verbose", "--file", str(explicit_file)] + if micromamba: + return [micromamba, "install", "--yes", "--verbose", "--file", str(explicit_file)] + return [conda_exe, "install", "--solver=libmamba", "--yes", "--verbose", "--file", str(explicit_file)] + + + +def _parse_conda_list_versions(lock_dir: Path) -> dict[str, str]: + path = lock_dir / "conda-list.json" + if not path.exists(): + return {} + data = load_json(path) + out: dict[str, str] = {} + if isinstance(data, list): + for row in data: + name = str(row.get("name") or "").strip().lower().replace("_", "-") + version = str(row.get("version") or "").strip() + channel = str(row.get("channel") or "") + if not name or not version: + continue + if "pypi" in channel.lower() or name not in out: + out[name] = version + return out + + +def _candidate_line_for_remaining_install(raw_line: str, pypi_versions: dict[str, str]) -> Optional[str]: + line = normalize_pkg_line(raw_line) + name = parse_name(line) + if not name: + return None + if name in PROTECTED_NAMES or is_protected_method_name(name) or is_core_override_name(name): + return None + if any(p.search(line) for p in SKIP_PATTERNS): + return None + if any(p.search(line) for p in DEFER_PATTERNS): + return None + if AV_LINE_RE.match(line): + return None + if " @ file:///" in line: + version = pypi_versions.get(name) + if version: + return f"{name}=={version}" + return None + if line.startswith("-e ") or line.startswith("--editable"): + return None + return line + + +def install_remaining_from_full_lock(lock_dir: Path, msvc_mode: str) -> None: + full_lock = pip_lock_filename(lock_dir) + if not full_lock.exists(): + print("[WARN] No full pip lock found; skipping remaining-full install.") + return + + current_names = {parse_name(x) for x in normalized_current_pip_lines()} + pypi_versions = _parse_conda_list_versions(lock_dir) + wanted: list[str] = [] + skipped: list[str] = [] + + for raw in normalize_lines(read_text(full_lock), kind="pip"): + cand = _candidate_line_for_remaining_install(raw, pypi_versions) + if not cand: + skipped.append(normalize_pkg_line(raw)) + continue + name = parse_name(cand) + if name in current_names: + continue + wanted.append(cand) + + wanted = list(dict.fromkeys(wanted)) + skipped = list(dict.fromkeys(skipped)) + + write_text(lock_dir / ".tmp-full-remaining-install.txt", "\n".join(wanted) + ("\n" if wanted else "")) + write_text(lock_dir / ".tmp-full-remaining-skipped.txt", "\n".join(skipped) + ("\n" if skipped else "")) + + if not wanted: + print("[INFO] No additional remaining pip deps to install from full lock.") + return + + print(f"[INFO] Installing {len(wanted)} remaining pip deps from full lock...") + install_requirements_file(lock_dir, msvc_mode, wanted, lock_dir / ".tmp-full-remaining-install.txt") + + + + +def restore_core_overrides(lock_dir: Path, msvc_mode: str) -> None: + current_direct = installed_direct_url_map() + restore_specs: list[str] = [] + + for _, spec in NERFSTUDIO_CORE_OVERRIDES.items(): + install_ref = str(spec.get("install_ref", "")).strip() + if not install_ref: + continue + pip_names = [str(x).strip().lower().replace("_", "-") for x in spec.get("pip_names", set())] + matched = False + for pip_name in pip_names: + cur_direct = current_direct.get(pip_name, "") + if git_requirement_matches(cur_direct, install_ref): + matched = True + break + if not matched: + restore_specs.append(install_ref) + + restore_specs = list(dict.fromkeys(restore_specs)) + if not restore_specs: + print("[INFO] Core overrides already aligned with standard install refs.") + return + + print("[INFO] Restoring core overrides to standard install refs: " + ", ".join(restore_specs)) + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "--no-build-isolation", + "--no-cache-dir", + *restore_specs, + ], + msvc_mode, + ) + +def restore_protected_from_lock(lock_dir: Path, msvc_mode: str) -> None: + full_lock = pip_lock_filename(lock_dir) + if not full_lock.exists(): + print("[WARN] No full pip lock found; cannot restore protected packages.") + return + + locked: dict[str, str] = {} + for raw in normalize_lines(read_text(full_lock), kind="pip"): + line = normalize_pkg_line(raw) + name = parse_name(line) + if name in PROTECTED_NAMES: + locked[name] = line + + build_plan = load_build_plan(lock_dir) + locked["numpy"] = build_plan.get("numpy_stable") or locked.get("numpy") or DEFAULT_NUMPY + + torch_lines = build_plan.get("torch_preinstall") or [] + for tl in torch_lines: + locked[parse_name(tl)] = tl + + current = {parse_name(x): x for x in normalized_current_pip_lines()} + current_direct = installed_direct_url_map() + + restore_specs: list[str] = [] + + for name, spec in locked.items(): + cur = current.get(name, "") + if spec and cur != spec and " @ file:///" not in spec: + restore_specs.append(spec) + + for name, git_spec in PROTECTED_GIT_PACKAGES.items(): + if is_core_override_name(name): + continue + cur_direct = current_direct.get(name, "") + if not git_requirement_matches(cur_direct, git_spec): + restore_specs.append(git_spec) + + restore_specs = list(dict.fromkeys(restore_specs)) + + if not restore_specs: + print("[INFO] Protected packages already aligned with lock.") + return + + print( + "[INFO] Restoring protected packages to locked versions: " + + ", ".join(parse_name(x) for x in restore_specs) + ) + + torch_specs = [x for x in restore_specs if parse_name(x) in {"torch", "torchvision", "torchaudio"}] + other_specs = [x for x in restore_specs if parse_name(x) not in {"torch", "torchvision", "torchaudio"}] + + if torch_specs: + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + *torch_specs, + "--index-url", + TORCH_INDEX, + ], + msvc_mode, + ) + + if other_specs: + install_requirements_file(lock_dir, msvc_mode, other_specs, lock_dir / ".tmp-protected-restore.txt") + +def print_strict_alignment_status(lock_dir: Path) -> None: + plan = load_build_plan(lock_dir) + pip_current = normalized_current_pip_lines() + pip_set = {parse_name(x): x for x in pip_current} + pip_direct = installed_direct_url_map() + + strict_names = [ + "numpy", + "torch", + "torchvision", + "torchaudio", + "torch-scatter", + "tinycudann", + "tiny-cuda-nn", + "nerfstudio", + "nerfacc", + "gsplat", + "viser", + "huggingface-hub", + "bitsandbytes", + "tyro", + "pycolmap", + "protobuf", + "matplotlib", + ] + + print("[INFO] Strict alignment status:") + print(f" [TARGET NUMPY] {plan.get('numpy_stable', DEFAULT_NUMPY)}") + + for name in strict_names: + if name == "pycolmap": + cur = pip_direct.get("pycolmap", "") or pip_set.get("pycolmap", "") + if git_requirement_matches(cur, PYCOLMAP_GIT): + print(f" [OK] pycolmap @ {PYCOLMAP_GIT}") + elif cur: + print(f" [DRIFT] {cur}") + else: + print(" [MISS] pycolmap") + continue + + if name in {"tinycudann", "tiny-cuda-nn"}: + cur = pip_direct.get("tinycudann", "") or pip_direct.get("tiny-cuda-nn", "") or pip_set.get("tinycudann", "") + if git_requirement_matches(cur, TCNN_GIT): + print(f" [OK] tinycudann @ {TCNN_GIT}") + elif cur: + print(f" [DRIFT] {cur}") + else: + print(f" [MISS] {name}") + continue + + if name in pip_set: + print(f" [OK] {pip_set[name]}") + else: + print(f" [MISS] {name}") + + print(f" [RUNTIME tinycudann] {'OK' if detect_tcnn_runtime() else 'MISSING'}") + +def repin(lock_dir: Path, *, skip_conda: bool = False, force_conda: bool = False, conda_exe: Optional[str] = None, msvc_mode: str = "") -> int: + conda_lock = find_conda_lock(lock_dir) + if conda_lock and not skip_conda: + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + print(f"[DEBUG] Using conda executable: {conda_exe}") + print(f"[DEBUG] CONDA_PREFIX={os.environ.get('CONDA_PREFIX')}") + if force_conda: + if conda_exe and os.environ.get("CONDA_PREFIX"): + cmd = choose_conda_restore_cmd(conda_exe, conda_lock) + print(f"[INFO] Re-applying exact conda lock with verbose restore from: {conda_lock}") + print_run(cmd) + elif conda_exe: + print("[WARN] Conda lock found, but current shell is not an active conda env; skipping conda repin.") + else: + print("[WARN] Conda lock found, but conda is not on PATH; skipping conda repin.") + else: + print("[INFO] Existing-env repin defaults to pip-layer replay only.") + print("[INFO] Use --force-conda if you explicitly want a full verbose conda restore in-place.") + elif skip_conda: + print("[INFO] Skipping conda layer by request.") + + replay_lock = replay_pip_filename(lock_dir) + pip_lock = replay_lock if replay_lock.exists() else pip_lock_filename(lock_dir) + if not pip_lock.exists(): + print("[WARN] No pip lock found.") + return 0 + + installer = load_installer_selection(lock_dir) + effective_msvc = str(installer.get("preferred_msvc") or msvc_mode or os.environ.get("PREFERRED_MSVC") or "").strip() + plan = load_build_plan(lock_dir) + numpy_spec = plan.get("numpy_stable") or DEFAULT_NUMPY + tcnn_arch = str((plan.get("tinycudann") or {}).get("cuda_arch", "")).strip() or current_tcnn_arch() + torch_lines, pyg_lines, tcnn_line, bulk, deferred, av_lines = split_pip_lock(read_text(pip_lock), lock_dir) + + if pip_lock.name == "pip-freeze-replay.txt": + print(f"[INFO] Re-applying replay-safe pip lock from: {pip_lock}") + else: + print(f"[INFO] Re-applying exact pip lock from: {pip_lock}") + + state: dict = {} + install_packaging_base(lock_dir, effective_msvc) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="bootstrap") + install_torch_preinstall(lock_dir, effective_msvc, torch_lines, numpy_spec, state) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-torch") + install_pyg_wheels(lock_dir, effective_msvc, torch_lines, pyg_lines) + install_tcnn(lock_dir, effective_msvc, tcnn_line, tcnn_arch) + install_requirements_file(lock_dir, effective_msvc, bulk, lock_dir / ".tmp-bulk-install.txt") + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-bulk") + install_remaining_from_full_lock(lock_dir, effective_msvc) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-full-remaining") + install_deferred(lock_dir, effective_msvc, deferred) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-deferred") + install_av(lock_dir, effective_msvc, av_lines) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-av") + restore_core_overrides(lock_dir, effective_msvc) + restore_protected_from_lock(lock_dir, effective_msvc) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-protected-restore") + print_strict_alignment_status(lock_dir) + return 0 + + +def create_env(lock_dir: Path, *, env_name: str, conda_exe: Optional[str] = None, force_repin: bool = True, msvc_mode: str = "") -> int: + conda_lock = find_conda_lock(lock_dir) + if not conda_lock: + print("[ERROR] No conda explicit lock found.") + return 1 + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + if not conda_exe: + print("[ERROR] Could not locate conda executable.") + return 1 + print(f"[INFO] Creating new env from lock: {env_name}") + print_run([conda_exe, "create", "--solver=libmamba", "--yes", "--name", env_name, "--file", str(conda_lock), "--verbose"]) + if force_repin: + print(f"[INFO] Running staged pip replay into env: {env_name}") + cmd = [conda_exe, "run", "-n", env_name, "python", str(ROOT / "deps_lock.py"), "--lock-dir", str(lock_dir), "--conda-exe", conda_exe] + if msvc_mode: + cmd.extend(["--msvc-mode", msvc_mode]) + cmd.extend(["repin", "--skip-conda"]) + print_run(cmd) + return 0 + +def apply_extra_patches(root_dir: Path) -> None: + patch_root = root_dir / "Extra-Methods-Patches" + + if not patch_root.exists(): + print("[INFO] No Extra-Methods-Patches directory found; skipping.") + return + + print("[INFO] Applying external patch tree...") + + for src in patch_root.rglob("*"): + if src.is_dir(): + continue + + rel = src.relative_to(patch_root) + dst = root_dir / rel + + if not dst.exists(): + print(f"[WARN] Target missing for patch: {dst}") + continue + + backup = dst.with_suffix(dst.suffix + ".orig") + if not backup.exists(): + shutil.copy2(dst, backup) + + shutil.copy2(src, dst) + print(f"[PATCH] {rel}") + +def install_editable(project_dir: Path, lock_dir: Path, msvc_mode: str) -> int: + installer = load_installer_selection(lock_dir) + effective_msvc = str(installer.get("preferred_msvc") or msvc_mode or os.environ.get("PREFERRED_MSVC") or "").strip() + print(f"[INFO] Installing editable project without dependency mutation: {project_dir}") + print_run_bootstrapped( + lock_dir, + [sys.executable, "-m", "pip", "install", *PIP_VERBOSE_ARGS, "--no-deps", "-e", str(project_dir)], + effective_msvc, + ) + return 0 + + +def build_parser() -> argparse.ArgumentParser: + p = argparse.ArgumentParser(description="Snapshot and restore an exact conda/pip dependency baseline with shell-level MSVC/CUDA bootstrap.") + p.add_argument("--lock-dir", default=str(DEFAULT_LOCK_DIR), help="Lock directory") + p.add_argument("--conda-exe", default=os.environ.get("CONDA_EXE"), help="Explicit conda executable (portable override)") + p.add_argument("--msvc-mode", default="", choices=["", "auto", "14.38", "14", "system"], help="Preferred MSVC toolset mode for builds (optional)") + sub = p.add_subparsers(dest="cmd", required=True) + sub.add_parser("export", help="Snapshot current active env") + sub.add_parser("check", help="Compare current env with lock") + rep = sub.add_parser("repin", help="Replay lock into current active env") + rep.add_argument("--skip-conda", action="store_true", help="Skip conda explicit lock replay") + rep.add_argument("--force-conda", action="store_true", help="Force a full verbose conda in-place restore before staged pip replay") + cre = sub.add_parser("create", help="Create a new conda env from explicit lock, then replay pip layer") + cre.add_argument("--env-name", required=True, help="Target conda env name") + cre.add_argument("--no-repin", action="store_true", help="Create env from conda explicit lock only, skip pip staged replay") + ed = sub.add_parser("editable", help="Install repo editable without dependency resolution") + ed.add_argument("project_dir", nargs="?", default=".") + return p + + +def main(argv: Optional[list[str]] = None) -> int: + args = build_parser().parse_args(argv) + lock_dir = Path(args.lock_dir).resolve() + if getattr(args, "msvc_mode", ""): + os.environ["PREFERRED_MSVC"] = args.msvc_mode + print(f"[INFO] Preferred MSVC mode: {args.msvc_mode}") + try: + if args.cmd == "export": + return export_locks(lock_dir, conda_exe=args.conda_exe, msvc_mode=args.msvc_mode) + if args.cmd == "check": + return check_locks(lock_dir, conda_exe=args.conda_exe) + if args.cmd == "repin": + return repin(lock_dir, skip_conda=args.skip_conda, force_conda=args.force_conda, conda_exe=args.conda_exe, msvc_mode=args.msvc_mode) + if args.cmd == "create": + return create_env(lock_dir, env_name=args.env_name, conda_exe=args.conda_exe, force_repin=not args.no_repin, msvc_mode=args.msvc_mode) + if args.cmd == "editable": + return install_editable(Path(args.project_dir).resolve(), lock_dir, args.msvc_mode) + raise AssertionError(args.cmd) + except subprocess.CalledProcessError as e: + cmd = e.cmd if isinstance(e.cmd, str) else " ".join(str(x) for x in e.cmd) + print(f"[ERROR] Command failed with exit code {e.returncode}: {cmd}") + return e.returncode or 1 + except RuntimeError as e: + print(f"[ERROR] {e}") + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) \ No newline at end of file diff --git a/deps_lock.py.bak b/deps_lock.py.bak new file mode 100644 index 0000000000..9fd91df9b3 --- /dev/null +++ b/deps_lock.py.bak @@ -0,0 +1,1883 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import argparse +import json +import os +import platform +import re +import shutil +import subprocess +import sys +import tempfile +from datetime import datetime, timezone +from pathlib import Path +from typing import Optional + +ROOT = Path(__file__).resolve().parent +DEFAULT_LOCK_DIR = ROOT / "deps-lock" +DEFAULT_NUMPY = "numpy==1.26.4" +DEFAULT_TORCH = [ + "torch==2.1.2+cu118", + "torchvision==0.16.2+cu118", +] +TORCH_INDEX = "https://download.pytorch.org/whl/cu118" +PYG_INDEX_TEMPLATE = "https://data.pyg.org/whl/{torch_tag}.html" +TCNN_GIT = "git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch" +PIP_VERBOSE_ARGS = ["-v"] +PYCOLMAP_GIT = "git+https://github.com/rmbrualla/pycolmap.git" + +PROTECTED_NAMES = { + "numpy", + "torch", + "torchvision", + "torchaudio", + "tinycudann", + "tiny-cuda-nn", + "torch-scatter", + "torch-sparse", + "torch-cluster", + "torch-spline-conv", + "nerfstudio", + "nerfacc", + "gsplat", + "viser", + "huggingface-hub", + "bitsandbytes", + "tyro", + "opencv-python", + "opencv-contrib-python", + "pycolmap", + "cuda-backend", + "protobuf", + "matplotlib", +} + +PROTECTED_PACKAGES = { + "numpy", + "torch", + "torchvision", + "torchaudio", + "tinycudann", + "nerfstudio", + "nerfacc", + "gsplat", + "viser", + "huggingface-hub", + "huggingface_hub", + "bitsandbytes", + "tyro", + "protobuf", + "matplotlib", + "torch-scatter", + "torch_scatter", +} + +PROTECTED_GIT_PACKAGES = { + "tinycudann": TCNN_GIT, + "tiny-cuda-nn": TCNN_GIT, + "pycolmap": PYCOLMAP_GIT, +} + +BUILD_TOOL_PKGS = [ + "pip", + "setuptools", + "wheel", + "Cython", + "pkgconfig", + "pybind11", +] + +STRICT_ALIGNMENT_NAMES = [ + "numpy", + "torch", + "torchvision", + "torchaudio", + "tinycudann", + "nerfstudio", + "nerfacc", + "gsplat", + "viser", + "huggingface-hub", + "bitsandbytes", + "tyro", + "pycolmap", + "protobuf", + "matplotlib", + "torch-scatter", +] + +TORCH_LINE_RE = re.compile(r"^(torch|torchvision|torchaudio)==", re.I) +PYG_LINE_RE = re.compile(r"^torch[-_](scatter|sparse|cluster|spline[-_]conv)==", re.I) +AV_LINE_RE = re.compile(r"^av==", re.I) +PYWIN32_BAD_RE = re.compile(r"^pywin32==305\.1$", re.I) +TCNN_REQ_RE = re.compile(r"^(tinycudann|tiny-cuda-nn)(==|\s*@\s*)", re.I) + +SKIP_PATTERNS = [ + re.compile(r"^-e\s+\.", re.I), + re.compile(r"^-e\s+.+nerfstudio", re.I), + re.compile(r"^\S+\s*@\s*file:///", re.I), + re.compile(r"^cuda_backend==", re.I), + re.compile(r"^av==", re.I), + re.compile(r"^torch==", re.I), + re.compile(r"^torchvision==", re.I), + re.compile(r"^torchaudio==", re.I), + re.compile(r"^torch[-_]scatter==", re.I), + re.compile(r"^torch[-_]sparse==", re.I), + re.compile(r"^torch[-_]cluster==", re.I), + re.compile(r"^torch[-_]spline[-_]conv==", re.I), + re.compile(r"^numpy(==|<|<=|>=|>|~=)", re.I), +] +DEFER_PATTERNS = [ + re.compile(r"^tinycudann\s*@\s*git\+https://github.com/NVlabs/tiny-cuda-nn/", re.I), + re.compile(r"^tiny-cuda-nn\s*@\s*git\+https://github.com/NVlabs/tiny-cuda-nn/", re.I), + re.compile(r"^tinycudann==", re.I), + re.compile(r"^tiny-cuda-nn==", re.I), +] + + +def run( + cmd: list[str], + *, + check: bool = True, + capture: bool = True, + env: Optional[dict] = None, +) -> subprocess.CompletedProcess: + return subprocess.run( + cmd, + check=check, + capture_output=capture, + text=True, + env=env, + encoding="utf-8", + errors="replace", + ) + + +def print_run(cmd: list[str], *, env: Optional[dict] = None) -> None: + print(f"[RUN] {' '.join(str(x) for x in cmd)}") + subprocess.run(cmd, check=True, env=env) + + +def run_quiet(cmd: list[str], *, env: Optional[dict] = None) -> str: + try: + cp = subprocess.run( + cmd, + capture_output=True, + text=True, + env=env, + check=False, + encoding="utf-8", + errors="replace", + ) + out = (cp.stdout or cp.stderr or "").strip() + return out[:4000] + except Exception as e: + return f"" + + +def which(name: str) -> Optional[str]: + return shutil.which(name) + + +def ensure_dir(path: Path) -> None: + path.mkdir(parents=True, exist_ok=True) + + +def write_text(path: Path, text: str) -> None: + ensure_dir(path.parent) + path.write_text(text, encoding="utf-8", newline="\n") + + +def read_text(path: Path) -> str: + return path.read_text(encoding="utf-8-sig") + + +def load_json(path: Path) -> dict: + if not path.exists(): + return {} + try: + return json.loads(read_text(path)) + except Exception: + return {} + + +def current_platform_guess() -> str: + sysname = platform.system().lower() + machine = platform.machine().lower() + if sysname == "windows": + return "win-arm64" if machine in {"arm64", "aarch64"} else "win-64" + if sysname == "linux": + return "linux-aarch64" if machine in {"arm64", "aarch64"} else "linux-64" + if sysname == "darwin": + return "osx-arm64" if machine in {"arm64", "aarch64"} else "osx-64" + return f"{sysname}-{machine}" + + +def conda_explicit_filename(lock_dir: Path, platform_tag: str) -> Path: + return lock_dir / f"conda-explicit-{platform_tag}.txt" + + +def pip_lock_filename(lock_dir: Path) -> Path: + return lock_dir / "pip-freeze-all.txt" + + +def replay_pip_filename(lock_dir: Path) -> Path: + return lock_dir / "pip-freeze-replay.txt" + + +def build_plan_filename(lock_dir: Path) -> Path: + return lock_dir / "build-plan.json" + + +def meta_filename(lock_dir: Path) -> Path: + return lock_dir / "lock-meta.json" + + +def numpy_audit_filename(lock_dir: Path) -> Path: + return lock_dir / "numpy-compat-audit.txt" + + +def msvc_log_filename(lock_dir: Path) -> Path: + return lock_dir / "msvc-toolsets.txt" + + +def msvc_selected_filename(lock_dir: Path) -> Path: + return lock_dir / "msvc-selected.txt" + + +def installer_selection_filename(lock_dir: Path) -> Path: + return lock_dir / "installer-selection.json" + + +def load_build_plan(lock_dir: Path) -> dict: + return load_json(build_plan_filename(lock_dir)) + + +def load_installer_selection(lock_dir: Path) -> dict: + return load_json(installer_selection_filename(lock_dir)) + + +def write_msvc_selected_log(lock_dir: Path, text: str) -> None: + write_text(msvc_selected_filename(lock_dir), text.rstrip() + "\n") + + +def normalize_lines(text: str, *, kind: str) -> list[str]: + out: list[str] = [] + for raw in text.replace("\r\n", "\n").replace("\r", "\n").split("\n"): + line = raw.strip() + if not line or line.startswith("#"): + continue + if kind == "pip" and (line.startswith("-e ") or line.startswith("--editable")): + continue + out.append(line) + return out + + +def normalize_pkg_line(line: str) -> str: + line = line.strip() + if PYWIN32_BAD_RE.match(line): + return "pywin32==305" + return line + + +def parse_name(line: str) -> str: + if " @ " in line: + return line.split(" @ ", 1)[0].strip().lower().replace("_", "-") + for sep in ("==", "<=", ">=", "~=", "<", ">"): + if sep in line: + return line.split(sep, 1)[0].strip().lower().replace("_", "-") + return line.strip().lower().replace("_", "-") + + +def torch_pyg_tag(torch_line: str) -> str: + return torch_line.replace("==", "-") + + +def detect_tcnn_runtime() -> bool: + try: + cp = run([sys.executable, "-c", "import tinycudann as tcnn; print('OK')"], check=False) + return cp.returncode == 0 + except Exception: + return False + + +def normalized_current_pip_lines() -> list[str]: + try: + cp = run([sys.executable, "-m", "pip", "freeze", "--all"]) + except subprocess.CalledProcessError: + cp = run([sys.executable, "-m", "pip", "freeze"]) + return [normalize_pkg_line(x) for x in normalize_lines(cp.stdout, kind="pip")] + +def installed_pip_map() -> dict[str, str]: + return {parse_name(x): normalize_pkg_line(x) for x in normalized_current_pip_lines()} + +def installed_direct_url_map() -> dict[str, str]: + cp = subprocess.run( + [sys.executable, "-m", "pip", "freeze", "--all"], + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + check=False, + ) + out: dict[str, str] = {} + for raw in normalize_lines(cp.stdout, kind="pip"): + line = normalize_pkg_line(raw) + if " @ " not in line: + continue + name = parse_name(line) + out[name] = line + return out + + +def git_requirement_matches(installed_line: str, expected_git: str) -> bool: + a = (installed_line or "").strip().lower() + b = (expected_git or "").strip().lower() + return bool(a) and bool(b) and b in a + +def spec_is_exact_pin(spec: str) -> bool: + line = normalize_pkg_line(spec) + return "==" in line and " @ " not in line and not line.startswith(("-", "--")) + + +def filter_already_installed_exact_specs(lines: list[str]) -> tuple[list[str], list[str]]: + installed = installed_pip_map() + pending: list[str] = [] + skipped: list[str] = [] + for raw in lines: + line = normalize_pkg_line(raw) + if spec_is_exact_pin(line): + name = parse_name(line) + if installed.get(name, "") == line: + skipped.append(line) + continue + pending.append(line) + return pending, skipped + + + +def find_conda_lock(lock_dir: Path) -> Optional[Path]: + matches = sorted(lock_dir.glob("conda-explicit-*.txt")) + if matches: + platform_tag = current_platform_guess() + platform_match = lock_dir / f"conda-explicit-{platform_tag}.txt" + if platform_match.exists(): + return platform_match + return matches[0] + fallback = lock_dir / "conda-explicit.txt" + return fallback if fallback.exists() else None + + +def parse_platform_from_explicit(explicit_text: str) -> str: + for line in explicit_text.splitlines(): + m = re.match(r"\s*#\s*platform:\s*(\S+)", line) + if m: + return m.group(1) + return current_platform_guess() + + + +def _looks_like_windows_path(value: str) -> bool: + v = (value or "").strip() + return bool(re.match(r"^[A-Za-z]:\\", v) or re.match(r"^\\\\", v)) + + +def _strip_wrapping_quotes(value: str) -> str: + v = (value or "").strip() + while len(v) >= 2 and ((v[0] == '"' and v[-1] == '"') or (v[0] == "'" and v[-1] == "'")): + v = v[1:-1].strip() + return v + + +def sanitize_windows_path(value: str) -> str: + v = (value or "").strip() + if not v: + return "" + + # normalize slash style first, but do not aggressively collapse all backslashes + v = v.replace("/", "\\") + v = v.replace('\"', '"').replace("\'", "'") + v = _strip_wrapping_quotes(v) + + # repair malformed values like: + # C:\"C:\Program Files\... + # C:\"C:\PROGRA~1\... + # C:"C:\Program Files\... + m = re.match(r'^[A-Za-z]:(?:\\?["\']+)([A-Za-z]:\\.*)$', v) + if m: + v = m.group(1).strip() + + # remove leading/trailing stray quotes around an actual drive path + if len(v) >= 2 and v[0] == '"' and _looks_like_windows_path(v[1:]): + v = v[1:] + if len(v) >= 2 and v[-1] == '"' and _looks_like_windows_path(v[:-1]): + v = v[:-1] + + v = v.strip().strip('"').strip("'").strip() + + # collapse accidental doubled backslashes after drive/share prefix normalization + if _looks_like_windows_path(v): + drive_m = re.match(r'^([A-Za-z]:\\)(.*)$', v) + unc_m = re.match(r'^(\\\\[^\\]+\\[^\\]+\\?)(.*)$', v) + if drive_m: + prefix, rest = drive_m.groups() + rest = re.sub(r'\\+', r'\\', rest) + v = prefix + rest + elif unc_m: + prefix, rest = unc_m.groups() + rest = re.sub(r'\\+', r'\\', rest) + v = prefix + rest + + # keep directory paths as directories, but trim file-path trailing separators + if re.search(r'\.(exe|bat|cmd)$', v, re.I): + v = v.rstrip("\\/") + + return os.path.normpath(v) if v else "" + + +def to_short_path(path_value: str) -> str: + path_value = sanitize_windows_path(path_value) + if not path_value: + return "" + + if platform.system().lower() != "windows": + return path_value + + # Prefer the clean normalized long path. Use 8.3 only as a fallback. + try: + if Path(path_value).exists(): + return os.path.normpath(path_value) + except Exception: + pass + + try: + cp = subprocess.run( + ["cmd", "/d", "/s", "/c", f'for %I in ("{path_value}") do @echo %~sI'], + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + check=False, + ) + out = sanitize_windows_path((cp.stdout or "").strip()) + if cp.returncode == 0 and out and _looks_like_windows_path(out): + return os.path.normpath(out) + except Exception: + pass + + return os.path.normpath(path_value) + + +def normalize_windows_path_list(value: str) -> str: + if platform.system().lower() != "windows": + return value or "" + + parts: list[str] = [] + seen: set[str] = set() + + for raw in (value or "").split(os.pathsep): + item = sanitize_windows_path(raw) + if not item: + continue + key = os.path.normcase(os.path.normpath(item)) + if key in seen: + continue + seen.add(key) + parts.append(os.path.normpath(item)) + + return os.pathsep.join(parts) +def short_toolset_version(version: str) -> str: + version = (version or "").strip() + if not version: + return "" + parts = version.split(".") + if len(parts) >= 2: + return f"{parts[0]}.{parts[1]}" + return version + + +def normalize_selected_toolset(selected: dict | None) -> dict | None: + if not selected: + return None + out = dict(selected) + full = (out.get("toolset_full") or out.get("toolset") or "").strip() + out["toolset_full"] = full + out["toolset_short"] = short_toolset_version(full) + out["toolset"] = full + return out + + +def vswhere_path() -> Optional[str]: + candidates = [ + os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", "Installer", "vswhere.exe"), + os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", "Installer", "vswhere.exe"), + ] + for c in candidates: + if c and os.path.exists(c): + return c + return None + + +def list_msvc_toolsets() -> list[dict]: + if platform.system().lower() != "windows": + return [] + out: list[dict] = [] + seen: set[tuple[str, str]] = set() + installs: list[Path] = [] + vswhere = vswhere_path() + if vswhere: + cp = run( + [ + vswhere, + "-products", + "*", + "-requires", + "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", + "installationPath", + ], + check=False, + ) + for line in cp.stdout.splitlines(): + line = line.strip() + if line: + installs.append(Path(line)) + for root in installs: + msvc_root = root / "VC" / "Tools" / "MSVC" + if not msvc_root.exists(): + continue + for d in sorted(msvc_root.iterdir()): + if not d.is_dir(): + continue + vcvarsall = root / "VC" / "Auxiliary" / "Build" / "vcvarsall.bat" + cl = d / "bin" / "Hostx64" / "x64" / "cl.exe" + if not (vcvarsall.exists() and cl.exists()): + continue + key = (str(root), d.name) + if key in seen: + continue + seen.add(key) + normalized = normalize_selected_toolset( + { + "installation": _norm_win_path(str(root)), + "toolset": d.name, + "vcvarsall": _norm_win_path(str(vcvarsall)), + "cl": _norm_win_path(str(cl)), + } + ) + if normalized: + out.append(normalized) + out.sort(key=lambda x: x["toolset_full"], reverse=True) + return out + +def ensure_build_tooling_for_cpp(lock_dir: Path, msvc_mode: str) -> None: + print("[INFO] Repairing Python build tooling required by native extensions...") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "pip", + "setuptools==75.1.0", + "wheel==0.44.0", + "Cython", + "pkgconfig", + "pybind11", + ], + msvc_mode, + ) + +def write_msvc_log(lock_dir: Path) -> list[dict]: + toolsets = list_msvc_toolsets() + lines: list[str] = [] + if not toolsets: + lines.append("No MSVC toolsets detected.") + else: + lines.append("Detected MSVC toolsets:") + for t in toolsets: + lines.append( + f"{t['toolset_full']} | short={t['toolset_short']} | " + f"install={t['installation']} | cl={t['cl']} | vcvarsall={t['vcvarsall']}" + ) + write_text(msvc_log_filename(lock_dir), "\n".join(lines) + "\n") + return toolsets + + +def choose_msvc_toolset(lock_dir: Path, requested: str) -> Optional[dict]: + toolsets = write_msvc_log(lock_dir) + requested = (requested or "").strip().lower() + if not toolsets or requested in {"", "system"}: + return None + if requested == "auto": + for t in toolsets: + if t["toolset_short"] == "14.38" or t["toolset_full"].startswith("14.38"): + return t + return toolsets[0] + if requested == "14": + for t in toolsets: + if t["toolset_full"].startswith("14."): + return t + return None + for t in toolsets: + if t["toolset_short"] == requested or t["toolset_full"].startswith(requested): + return t + return None + + +def detect_cuda_root() -> str: + candidates = [ + os.environ.get("CUDA_PATH", ""), + os.environ.get("CUDA_HOME", ""), + ] + for cand in candidates: + cand = (cand or "").strip().strip('"') + if cand and Path(cand).exists(): + return cand + nvcc = shutil.which("nvcc.exe") or shutil.which("nvcc") + if nvcc: + try: + return str(Path(nvcc).resolve().parent.parent) + except Exception: + pass + default_cuda = Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "NVIDIA GPU Computing Toolkit" / "CUDA" / "v11.8" + if default_cuda.exists(): + return str(default_cuda) + return "" + + +def detect_git_dirs() -> list[str]: + candidates: list[str] = [] + seen: set[str] = set() + + git_exe = shutil.which("git.exe") or shutil.which("git") + if git_exe: + gp = os.path.normpath(str(Path(git_exe).resolve().parent)) + key = os.path.normcase(gp) + if key not in seen: + seen.add(key) + candidates.append(gp) + + program_files = os.environ.get("ProgramFiles", r"C:\Program Files") + for p in ( + Path(program_files) / "Git" / "cmd", + Path(program_files) / "Git" / "bin", + ): + if p.exists(): + gp = os.path.normpath(str(p)) + key = os.path.normcase(gp) + if key not in seen: + seen.add(key) + candidates.append(gp) + + return candidates + + +def get_runtime_path_entries() -> list[str]: + entries: list[str] = [] + + conda_prefix = os.environ.get("CONDA_PREFIX", "") + if conda_prefix: + prefix = Path(conda_prefix) + for p in ( + prefix / "Scripts", + prefix, + prefix / "Library" / "bin", + prefix / "Library" / "usr" / "bin", + prefix / "bin", + ): + entries.append(str(p)) + + entries.append(str(Path(sys.executable).resolve().parent)) + entries.extend(detect_git_dirs()) + + return entries + +def _norm_win_path(value: str) -> str: + clean = sanitize_windows_path(value) + if not clean: + return "" + return os.path.normpath(clean) + +def _norm_win_list(values: list[str]) -> list[str]: + out: list[str] = [] + seen: set[str] = set() + + for v in values: + nv = _norm_win_path(v) + if not nv: + continue + key = nv.lower() + if key in seen: + continue + seen.add(key) + out.append(nv) + + return out + +def parse_set_output_to_env(text: str) -> dict[str, str]: + parsed_env: dict[str, str] = {} + + path_list_keys = {"PATH", "INCLUDE", "LIB", "LIBPATH"} + path_scalar_keys = { + "CC", + "CXX", + "CUDAHOSTCXX", + "CLCACHE_CL", + "CMAKE_CUDA_HOST_COMPILER", + "VCToolsInstallDir", + "VCINSTALLDIR", + "VSINSTALLDIR", + "CUDA_PATH", + "CUDA_HOME", + "CUDAToolkit_ROOT", + } + + for line in (text or "").splitlines(): + if "=" not in line: + continue + + k, v = line.split("=", 1) + k = k.strip() + if not k: + continue + + ku = k.upper() + + if ku in path_list_keys: + parsed_env[k] = normalize_windows_path_list(v) + elif ku in path_scalar_keys: + parsed_env[k] = _norm_win_path(v) + else: + parsed_env[k] = v.strip().replace('\\"', '"').replace('""', '"') + + return parsed_env + +def build_bootstrap_context(lock_dir: Path, requested: str) -> dict: + requested = (requested or "").strip() + installer = load_installer_selection(lock_dir) + + effective = str( + installer.get("preferred_msvc") + or requested + or os.environ.get("PREFERRED_MSVC") + or "" + ).strip() + + selected = None + cuda_root = "" + git_dirs: list[str] = [] + runtime_entries: list[str] = [] + + if platform.system().lower() == "windows": + selected = choose_msvc_toolset(lock_dir, effective) + selected = normalize_selected_toolset(selected) + + if selected: + selected = { + **selected, + "installation": _norm_win_path(selected.get("installation", "")), + "vcvarsall": _norm_win_path(selected.get("vcvarsall", "")), + "cl": _norm_win_path(selected.get("cl", "")), + } + + cuda_root = _norm_win_path(detect_cuda_root()) + git_dirs = _norm_win_list(detect_git_dirs()) + runtime_entries = _norm_win_list(get_runtime_path_entries()) + + ctx = { + "requested": effective, + "selected": selected, + "cuda_root": cuda_root, + "git_dirs": git_dirs, + "runtime_path_entries": runtime_entries, + } + + lines = [ + f"requested={effective or 'system'}", + f"cuda_root={cuda_root}", + f"git_dirs={';'.join(git_dirs)}", + f"runtime_path_entries={';'.join(runtime_entries)}", + ] + + if selected: + lines.extend( + [ + f"selected_toolset={selected['toolset_full']}", + f"selected_short={selected['toolset_short']}", + f"selected_install={selected['installation']}", + f"selected_cl={selected['cl']}", + f"selected_vcvarsall={selected['vcvarsall']}", + "mode=subprocess-shell-bootstrap", + ] + ) + else: + lines.append("mode=system/no-forced-toolset") + + write_msvc_selected_log(lock_dir, "\n".join(lines) + "\n") + return ctx + +def find_header_in_include(include_value: str, header_name: str) -> str: + header_name = (header_name or "").strip() + if not header_name: + return "" + + for raw in normalize_windows_path_list(include_value).split(os.pathsep): + root = _norm_win_path(raw) + if not root: + continue + try: + p = Path(root) / header_name + if p.exists(): + return str(p) + except Exception: + continue + + return "" + +def validate_msvc_from_shell(lock_dir: Path, ctx: dict) -> tuple[bool, list[str]]: + if platform.system().lower() != "windows": + return True, [] + + selected = ctx.get("selected") + if not selected: + return True, [] + + vcvarsall = _norm_win_path(selected.get("vcvarsall", "")) + cl = _norm_win_path(selected.get("cl", "")) + + errors: list[str] = [] + + if not vcvarsall or not Path(vcvarsall).exists(): + errors.append(f"vcvarsall missing: {vcvarsall}") + + if not cl or not Path(cl).exists(): + errors.append(f"cl.exe missing: {cl}") + + return len(errors) == 0, errors + + +def _cmdline_from_args(args: list[str]) -> str: + return subprocess.list2cmdline([str(x) for x in args]) + + +def _make_bootstrap_batch( + lock_dir: Path, + command: list[str], + msvc_mode: str, + extra_env: Optional[dict] = None, +) -> str: + ctx = build_bootstrap_context(lock_dir, msvc_mode) + ok, errors = validate_msvc_from_shell(lock_dir, ctx) + if not ok: + raise RuntimeError("MSVC bootstrap metadata invalid: " + "; ".join(errors)) + + selected = ctx.get("selected") + cuda_root = ctx.get("cuda_root", "") + runtime_entries = list(ctx.get("runtime_path_entries", [])) + extra_env = extra_env or {} + + lines: list[str] = [ + "@echo off", + "setlocal EnableExtensions", + ] + + if platform.system().lower() == "windows" and selected: + vcvarsall = _norm_win_path(selected["vcvarsall"]) + short_ver = selected["toolset_short"] + full_ver = selected["toolset_full"] + cl = _norm_win_path(selected["cl"]) + cl_dir = _norm_win_path(str(Path(cl).parent)) + + lines.extend( + [ + f'call "{vcvarsall}" x64 -vcvars_ver={short_ver}', + f'if errorlevel 1 call "{vcvarsall}" x64 -vcvars_ver={full_ver}', + f'if errorlevel 1 call "{vcvarsall}" x64', + "if errorlevel 1 exit /b %errorlevel%", + f'set "NS_SELECTED_MSVC_TOOLSET={full_ver}"', + f'set "NS_SELECTED_MSVC_CL={cl}"', + f'set "CC={cl}"', + f'set "CXX={cl}"', + f'set "CUDAHOSTCXX={cl}"', + f'set "CLCACHE_CL={cl}"', + f'set "CMAKE_CUDA_HOST_COMPILER={cl}"', + f'set "CMAKE_GENERATOR_TOOLSET=v143,version={full_ver}"', + 'set "DISTUTILS_USE_SDK=1"', + 'set "MSSdk=1"', + ] + ) + + if cuda_root: + cuda_root = _norm_win_path(cuda_root) + cuda_bin = _norm_win_path(str(Path(cuda_root) / "bin")) + + lines.extend( + [ + f'set "CUDA_PATH={cuda_root}"', + f'set "CUDA_HOME={cuda_root}"', + f'set "CUDAToolkit_ROOT={cuda_root}"', + ] + ) + + if Path(cuda_bin).exists(): + runtime_entries.insert(0, cuda_bin) + + merged_runtime = normalize_windows_path_list(os.pathsep.join(runtime_entries)) + if merged_runtime: + lines.append(f'set "PATH={merged_runtime};%PATH%"') + + # tiny-cuda-nn / torch cpp_extension can incorrectly pivot into ROCm mode on + # Windows when ROCm-related environment variables leak into the build shell. + # Force a clean CUDA-only build context for Windows extension builds. + if platform.system().lower() == "windows": + lines.extend( + [ + 'set "ROCM_HOME="', + 'set "ROCM_PATH="', + 'set "HIP_HOME="', + 'set "HIP_PATH="', + 'set "HCC_HOME="', + 'set "HIP_PATH_57="', + 'set "HIP_DEVICE_LIB_PATH="', + 'set "PYTORCH_ROCM_ARCH="', + ] + ) + + for k, v in extra_env.items(): + if v is None: + continue + sval = str(v) + if sval == "": + lines.append(f'set "{k}="') + continue + lines.append(f'set "{k}={sval.strip()}"') + + lines.append(_cmdline_from_args(command)) + lines.append("exit /b %errorlevel%") + return "\n".join(lines) + "\n" + + +def run_bootstrapped( + lock_dir: Path, + command: list[str], + msvc_mode: str, + *, + check: bool = True, + extra_env: Optional[dict] = None, +) -> subprocess.CompletedProcess: + if platform.system().lower() != "windows": + return subprocess.run(command, check=check, capture_output=False, text=True) + + script = _make_bootstrap_batch(lock_dir, command, msvc_mode, extra_env=extra_env) + with tempfile.NamedTemporaryFile("w", suffix=".cmd", delete=False, encoding="utf-8", newline="\r\n") as f: + f.write(script) + temp_cmd = f.name + + try: + # Pass the temporary batch path as a raw argv element. Adding manual quotes here + # causes cmd.exe to receive an extra-quoted command like + # ""C:\path\tmp.cmd"", which then fails with + # "not recognized as an internal or external command". + return subprocess.run(["cmd", "/d", "/s", "/c", temp_cmd], check=check) + finally: + try: + os.unlink(temp_cmd) + except OSError: + pass + + +def print_run_bootstrapped( + lock_dir: Path, + command: list[str], + msvc_mode: str, + *, + extra_env: Optional[dict] = None, +) -> None: + print(f"[RUN] {' '.join(str(x) for x in command)}") + run_bootstrapped(lock_dir, command, msvc_mode, check=True, extra_env=extra_env) + + +def detect_torch_lines(lines: list[str]) -> list[str]: + found = [normalize_pkg_line(line) for line in lines if TORCH_LINE_RE.match(line)] + if not found: + return DEFAULT_TORCH[:] + uniq: list[str] = [] + for line in found: + if line not in uniq: + uniq.append(line) + return uniq + + +def detect_pyg_lines(lines: list[str]) -> list[str]: + uniq: list[str] = [] + for line in lines: + line = normalize_pkg_line(line) + if PYG_LINE_RE.match(line) and line not in uniq: + uniq.append(line) + return uniq + + +def detect_numpy_baseline(lines: list[str]) -> str: + for line in lines: + if line.lower().startswith("numpy=="): + version = line.split("==", 1)[1].strip() + if version and not version.startswith("2"): + return f"numpy=={version}" + return DEFAULT_NUMPY + + +def detect_tcnn_line(lines: list[str]) -> str: + for line in lines: + if TCNN_REQ_RE.match(line): + return normalize_pkg_line(line) + return TCNN_GIT + + +def current_tcnn_arch() -> str: + return os.environ.get("TCNN_CUDA_ARCHITECTURES", "").strip() + + +def torch_cuda_arch_list_value(value: str) -> str: + value = (value or "").strip() + if not value: + return "" + m = re.fullmatch(r"(\d)(\d)(?:\+PTX)?", value, re.I) + if m: + major, minor = m.group(1), m.group(2) + suffix = "+PTX" if value.upper().endswith("+PTX") else "" + return f"{major}.{minor}{suffix}" + return value + + +def compute_replay_lines(lines: list[str]) -> list[str]: + replay: list[str] = [] + for raw in lines: + line = normalize_pkg_line(raw) + if any(p.search(line) for p in SKIP_PATTERNS): + continue + if any(p.search(line) for p in DEFER_PATTERNS): + continue + replay.append(line) + return replay + + +def export_numpy_audit(lock_dir: Path, lines: list[str], plan: dict) -> None: + rows = [] + for line in lines: + name = parse_name(line) + if name.startswith("numpy") or name in {"torch", "torchvision", "torchaudio", "opencv-python", "opencv-contrib-python", "matplotlib", "scipy", "pandas", "pycolmap", "open3d", "tensorflow"}: + rows.append(line) + rows.extend([f"PLAN torch_preinstall: {x}" for x in plan.get("torch_preinstall", [])]) + rows.extend([f"PLAN pyg_wheels: {x}" for x in plan.get("pyg_wheels", [])]) + rows.extend([f"PLAN deferred: {x}" for x in plan.get("deferred", [])]) + write_text(numpy_audit_filename(lock_dir), "\n".join(dict.fromkeys(rows)) + "\n") + + +def export_locks(lock_dir: Path, conda_exe: Optional[str] = None, msvc_mode: str = "") -> int: + ensure_dir(lock_dir) + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + platform_tag = current_platform_guess() + conda_lock_path: Optional[Path] = None + + print(f"[DEBUG] export_locks using conda executable: {conda_exe}") + print(f"[DEBUG] export_locks CONDA_PREFIX={os.environ.get('CONDA_PREFIX')}") + + if conda_exe and os.environ.get("CONDA_PREFIX"): + cp = run([conda_exe, "list", "--explicit", "--md5"]) + explicit = cp.stdout + platform_tag = parse_platform_from_explicit(explicit) + conda_lock_path = conda_explicit_filename(lock_dir, platform_tag) + write_text(conda_lock_path, explicit) + cp_json = run([conda_exe, "list", "--json"]) + write_text(lock_dir / "conda-list.json", cp_json.stdout) + else: + print("[WARN] Active conda environment not detected; skipping conda explicit export.") + + pip_lines = normalized_current_pip_lines() + write_text(pip_lock_filename(lock_dir), "\n".join(pip_lines) + "\n") + write_text(replay_pip_filename(lock_dir), "\n".join(compute_replay_lines(pip_lines)) + "\n") + + installer = load_installer_selection(lock_dir) + effective_msvc = str(installer.get("preferred_msvc") or msvc_mode or os.environ.get("PREFERRED_MSVC") or "").strip() + ctx = build_bootstrap_context(lock_dir, effective_msvc) + + numpy_baseline = detect_numpy_baseline(pip_lines) + build_plan = { + "numpy_stable": numpy_baseline, + "torch_preinstall": detect_torch_lines(pip_lines), + "torch_index": TORCH_INDEX, + "pyg_wheels": detect_pyg_lines(pip_lines), + "pyg_index_template": PYG_INDEX_TEMPLATE, + "tinycudann": { + "requirement": detect_tcnn_line(pip_lines), + "cuda_arch": str(installer.get("cuda_arch") or current_tcnn_arch() or "").strip(), + }, + "pycolmap": { + "requirement": PYCOLMAP_GIT, + }, + "deferred": [x for x in pip_lines if any(p.search(x) for p in DEFER_PATTERNS)], + "skipped_from_bulk": [x for x in pip_lines if any(p.search(x) for p in SKIP_PATTERNS)], + "build_tooling": BUILD_TOOL_PKGS, + "preferred_msvc": effective_msvc, + "bootstrap_mode": "subprocess-shell-bootstrap", + "selected_toolset": (ctx.get("selected") or {}).get("toolset_full", ""), + "selected_installation": (ctx.get("selected") or {}).get("installation", ""), + "cuda_root": ctx.get("cuda_root", ""), + } + write_text(build_plan_filename(lock_dir), json.dumps(build_plan, indent=2) + "\n") + export_numpy_audit(lock_dir, pip_lines, build_plan) + write_msvc_log(lock_dir) + + meta = { + "created_utc": datetime.now(timezone.utc).isoformat(), + "python_executable": sys.executable, + "python_version": sys.version, + "platform_guess": platform_tag, + "conda_executable": conda_exe, + "conda_env": os.environ.get("CONDA_DEFAULT_ENV"), + "conda_prefix": os.environ.get("CONDA_PREFIX"), + "conda_lock": conda_lock_path.name if conda_lock_path else None, + "pip_lock": pip_lock_filename(lock_dir).name, + "pip_replay": replay_pip_filename(lock_dir).name, + "build_plan": build_plan_filename(lock_dir).name, + "numpy_audit": numpy_audit_filename(lock_dir).name, + "msvc_log": msvc_log_filename(lock_dir).name, + "msvc_selected_log": msvc_selected_filename(lock_dir).name, + "installer_selection": installer_selection_filename(lock_dir).name if installer else None, + } + write_text(meta_filename(lock_dir), json.dumps(meta, indent=2) + "\n") + + print(f"[OK] Wrote pip lock: {pip_lock_filename(lock_dir)}") + print(f"[OK] Wrote replay-safe pip lock: {replay_pip_filename(lock_dir)}") + if conda_lock_path: + print(f"[OK] Wrote conda lock: {conda_lock_path}") + print(f"[OK] Wrote build plan: {build_plan_filename(lock_dir)}") + print(f"[OK] Wrote metadata: {meta_filename(lock_dir)}") + print(f"[OK] Wrote NumPy audit: {numpy_audit_filename(lock_dir)}") + print(f"[OK] Wrote MSVC toolset log: {msvc_log_filename(lock_dir)}") + print(f"[OK] Wrote MSVC selected log: {msvc_selected_filename(lock_dir)}") + return 0 + + +def diff_summary(expected: list[str], current: list[str], label: str) -> tuple[bool, str]: + if expected == current: + return True, f"[OK] {label} matches lock exactly." + expected_set = set(expected) + current_set = set(current) + missing = sorted(expected_set - current_set) + extra = sorted(current_set - expected_set) + lines = [f"[FAIL] {label} differs from lock."] + if missing: + lines.append(" Missing/changed (first 10):") + lines.extend([f" - {x}" for x in missing[:10]]) + if extra: + lines.append(" Extra/different (first 10):") + lines.extend([f" + {x}" for x in extra[:10]]) + return False, "\n".join(lines) + + +def check_locks(lock_dir: Path, conda_exe: Optional[str] = None) -> int: + ok = True + conda_lock = find_conda_lock(lock_dir) + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + print(f"[DEBUG] check_locks using conda executable: {conda_exe}") + print(f"[DEBUG] check_locks CONDA_PREFIX={os.environ.get('CONDA_PREFIX')}") + if conda_lock and conda_exe and os.environ.get("CONDA_PREFIX"): + current = run([conda_exe, "list", "--explicit", "--md5"]).stdout + good, msg = diff_summary( + normalize_lines(read_text(conda_lock), kind="conda"), + normalize_lines(current, kind="conda"), + "Conda explicit lock", + ) + print(msg) + ok &= good + elif conda_lock: + print("[WARN] Conda lock exists but current shell is not an active conda env; skipping conda check.") + else: + print("[WARN] No conda lock found.") + + pip_lock = pip_lock_filename(lock_dir) + if pip_lock.exists(): + current = normalized_current_pip_lines() + good, msg = diff_summary( + [normalize_pkg_line(x) for x in normalize_lines(read_text(pip_lock), kind="pip")], + current, + "pip freeze lock", + ) + print(msg) + ok &= good + else: + print("[WARN] No pip lock found.") + return 0 if ok else 2 + + +def get_installed_version(pkg_name: str) -> str: + cp = subprocess.run( + [sys.executable, "-m", "pip", "show", pkg_name], + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + ) + if cp.returncode != 0: + return "" + for line in cp.stdout.splitlines(): + if line.lower().startswith("version:"): + return line.split(":", 1)[1].strip() + return "" + + +def install_packaging_base(lock_dir: Path, msvc_mode: str) -> None: + print("[INFO] Installing build/runtime base tooling...") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + *BUILD_TOOL_PKGS, + ], + msvc_mode, + ) + + +def ensure_numpy_stable(lock_dir: Path, msvc_mode: str, numpy_spec: str, state: dict, *, reason: str) -> None: + desired = numpy_spec.split("==", 1)[1] if "==" in numpy_spec else "" + current = get_installed_version("numpy") + if state.get("numpy_version") == desired and current == desired: + print(f"[INFO] NumPy already stable at {desired}; skipping reinstall ({reason}).") + return + print(f"[INFO] Enforcing stable NumPy policy: {numpy_spec} ({reason})") + print_run_bootstrapped( + lock_dir, + [sys.executable, "-m", "pip", "install", *PIP_VERBOSE_ARGS, "--upgrade", "--force-reinstall", numpy_spec], + msvc_mode, + ) + state["numpy_version"] = desired or get_installed_version("numpy") + + +def install_torch_preinstall(lock_dir: Path, msvc_mode: str, torch_lines: list[str], numpy_spec: str, state: dict) -> None: + if not torch_lines: + torch_lines = DEFAULT_TORCH[:] + pending_torch, skipped_torch = filter_already_installed_exact_specs(torch_lines) + if skipped_torch: + print(f"[INFO] Skipping already-installed torch package(s): {', '.join(skipped_torch)}") + if not pending_torch: + print("[INFO] Torch stack already aligned with requested exact versions; skipping reinstall.") + state["numpy_version"] = numpy_spec.split("==", 1)[1] if "==" in numpy_spec else state.get("numpy_version", "") + return + print(f"[INFO] Installing torch stack first WITH dependencies: {', '.join(pending_torch)}") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + numpy_spec, + *pending_torch, + "--index-url", + TORCH_INDEX, + ], + msvc_mode, + ) + state["numpy_version"] = numpy_spec.split("==", 1)[1] if "==" in numpy_spec else state.get("numpy_version", "") + + +def install_pyg_wheels(lock_dir: Path, msvc_mode: str, torch_lines: list[str], pyg_lines: list[str]) -> None: + if not pyg_lines: + return + torch_line = next((x for x in torch_lines if x.lower().startswith("torch==")), DEFAULT_TORCH[0]) + index_url = PYG_INDEX_TEMPLATE.format(torch_tag=torch_pyg_tag(torch_line)) + pending_pyg, skipped_pyg = filter_already_installed_exact_specs(pyg_lines) + if skipped_pyg: + print(f"[INFO] Skipping already-installed PyG wheel(s): {', '.join(skipped_pyg)}") + for line in pending_pyg: + print(f"[INFO] Installing PyG wheel from prebuilt index: {line}") + print_run_bootstrapped( + lock_dir, + [sys.executable, "-m", "pip", "install", *PIP_VERBOSE_ARGS, line, "-f", index_url], + msvc_mode, + ) + + +def split_pip_lock(lock_text: str, lock_dir: Path) -> tuple[list[str], list[str], str, list[str], list[str], list[str]]: + lines = [normalize_pkg_line(x) for x in normalize_lines(lock_text, kind="pip")] + plan = load_build_plan(lock_dir) + torch_lines = plan.get("torch_preinstall") or detect_torch_lines(lines) + pyg_lines = plan.get("pyg_wheels") or detect_pyg_lines(lines) + tcnn_line = (plan.get("tinycudann") or {}).get("requirement") or detect_tcnn_line(lines) + torch_names = {parse_name(x) for x in torch_lines} + pyg_names = {parse_name(x) for x in pyg_lines} + bulk, deferred, av_lines = [], [], [] + for line in lines: + name = parse_name(line) + if name in torch_names or name in pyg_names or name == "numpy": + continue + if name in {"tinycudann", "tiny-cuda-nn"}: + continue + if AV_LINE_RE.match(line): + av_lines.append(line) + continue + if any(p.search(line) for p in DEFER_PATTERNS): + deferred.append(line) + continue + if any(p.search(line) for p in SKIP_PATTERNS): + continue + bulk.append(line) + return torch_lines, pyg_lines, tcnn_line, bulk, deferred, av_lines + + +def install_requirements_file(lock_dir: Path, msvc_mode: str, lines: list[str], tmp_path: Path) -> None: + if not lines: + return + cleaned = [normalize_pkg_line(x) for x in lines] + pending, skipped = filter_already_installed_exact_specs(cleaned) + if skipped: + print(f"[INFO] Skipping already-installed exact requirement(s): {', '.join(skipped[:20])}" + (" ..." if len(skipped) > 20 else "")) + if not pending: + print(f"[INFO] All requested exact requirements already installed for: {tmp_path.name}") + return + write_text(tmp_path, "\n".join(pending) + "\n") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "--no-deps", + "--no-build-isolation", + "-r", + str(tmp_path), + ], + msvc_mode, + ) + + +def install_tcnn(lock_dir: Path, msvc_mode: str, tcnn_line: str, tcnn_arch: str) -> None: + if tcnn_runtime_ok(tcnn_arch): + print("[INFO] tiny-cuda-nn already importable and working; skipping rebuild.") + return + if not tcnn_line: + return + try: + import tinycudann as tcnn # noqa: F401 + print("[INFO] tinycudann already importable and runtime-usable; skipping rebuild.") + return + except Exception: + pass + ensure_build_tooling_for_cpp(lock_dir, msvc_mode) + + try: + import pkg_resources # noqa: F401 + print("[INFO] pkg_resources available.") + except Exception: + raise RuntimeError("pkg_resources is still unavailable after setuptools repair.") + + print("[INFO] Installing tiny-cuda-nn torch bindings...") + print(f"[INFO] sys.executable={sys.executable}") + + if tcnn_arch: + print(f"[INFO] TCNN_CUDA_ARCHITECTURES={tcnn_arch}") + print(f"[INFO] TORCH_CUDA_ARCH_LIST={torch_cuda_arch_list_value(tcnn_arch)}") + + ctx = build_bootstrap_context(lock_dir, msvc_mode) + selected = ctx.get("selected") + if selected: + print(f"[INFO] Using bootstrapped MSVC toolset: {selected['toolset_full']}") + print(f"[INFO] Bootstrap log: {msvc_selected_filename(lock_dir)}") + + torch_arch_list = torch_cuda_arch_list_value(tcnn_arch) + extra_env = { + "FORCE_CUDA": "1", + "TORCH_CUDA_ARCH_LIST": torch_arch_list, + "MAX_JOBS": "1", + "CMAKE_BUILD_PARALLEL_LEVEL": "1", + "DISTUTILS_USE_SDK": "1", + "MSSdk": "1", + "ROCM_HOME": "", + "ROCM_PATH": "", + "HIP_HOME": "", + "HIP_PATH": "", + "HCC_HOME": "", + "HIP_PATH_57": "", + "HIP_DEVICE_LIB_PATH": "", + "PYTORCH_ROCM_ARCH": "", + } + if tcnn_arch: + extra_env["TCNN_CUDA_ARCHITECTURES"] = tcnn_arch + + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-c", + ( + "import os,sys; " + "print('[BOOTSTRAP CHECK] python=', sys.executable); " + "print('[BOOTSTRAP CHECK] CUDA_HOME=', os.environ.get('CUDA_HOME')); " + "print('[BOOTSTRAP CHECK] CUDA_PATH=', os.environ.get('CUDA_PATH')); " + "print('[BOOTSTRAP CHECK] TCNN_CUDA_ARCHITECTURES=', os.environ.get('TCNN_CUDA_ARCHITECTURES')); " + "print('[BOOTSTRAP CHECK] TORCH_CUDA_ARCH_LIST=', os.environ.get('TORCH_CUDA_ARCH_LIST'))" + ), + ], + msvc_mode, + extra_env=extra_env, + ) + + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "--no-build-isolation", + "--no-cache-dir", + TCNN_GIT, + ], + msvc_mode, + extra_env=extra_env, + ) + +def tcnn_runtime_ok(expected_arch=""): + import tinycudann as tcnn + import torch + return torch.cuda.is_available() + + +def install_deferred(lock_dir: Path, msvc_mode: str, lines: list[str]) -> None: + leftovers = [x for x in lines if not TCNN_REQ_RE.match(x)] + if leftovers: + print(f"[INFO] Installing deferred package(s): {', '.join(leftovers)}") + install_requirements_file(lock_dir, msvc_mode, leftovers, lock_dir / ".tmp-deferred-install.txt") + + +def install_av(lock_dir: Path, msvc_mode: str, lines: list[str]) -> None: + if not lines: + return + print("[INFO] Installing AV prerequisites, then AV...") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "setuptools<81", + "wheel", + "pip", + "Cython", + "pkgconfig", + "pybind11", + "numpy<2", + ], + msvc_mode, + ) + install_requirements_file(lock_dir, msvc_mode, lines, lock_dir / ".tmp-av-install.txt") + + +def choose_conda_restore_cmd(conda_exe: str, explicit_file: Path) -> list[str]: + mamba = which("mamba") or which("mamba.exe") + micromamba = which("micromamba") or which("micromamba.exe") + if mamba: + return [mamba, "install", "--yes", "--verbose", "--file", str(explicit_file)] + if micromamba: + return [micromamba, "install", "--yes", "--verbose", "--file", str(explicit_file)] + return [conda_exe, "install", "--solver=libmamba", "--yes", "--verbose", "--file", str(explicit_file)] + + + +def _parse_conda_list_versions(lock_dir: Path) -> dict[str, str]: + path = lock_dir / "conda-list.json" + if not path.exists(): + return {} + data = load_json(path) + out: dict[str, str] = {} + if isinstance(data, list): + for row in data: + name = str(row.get("name") or "").strip().lower().replace("_", "-") + version = str(row.get("version") or "").strip() + channel = str(row.get("channel") or "") + if not name or not version: + continue + if "pypi" in channel.lower() or name not in out: + out[name] = version + return out + + +def _candidate_line_for_remaining_install(raw_line: str, pypi_versions: dict[str, str]) -> Optional[str]: + line = normalize_pkg_line(raw_line) + name = parse_name(line) + if not name: + return None + if name in PROTECTED_NAMES: + return None + if any(p.search(line) for p in SKIP_PATTERNS): + return None + if any(p.search(line) for p in DEFER_PATTERNS): + return None + if AV_LINE_RE.match(line): + return None + if " @ file:///" in line: + version = pypi_versions.get(name) + if version: + return f"{name}=={version}" + return None + if line.startswith("-e ") or line.startswith("--editable"): + return None + return line + + +def install_remaining_from_full_lock(lock_dir: Path, msvc_mode: str) -> None: + full_lock = pip_lock_filename(lock_dir) + if not full_lock.exists(): + print("[WARN] No full pip lock found; skipping remaining-full install.") + return + + current_names = {parse_name(x) for x in normalized_current_pip_lines()} + pypi_versions = _parse_conda_list_versions(lock_dir) + wanted: list[str] = [] + skipped: list[str] = [] + + for raw in normalize_lines(read_text(full_lock), kind="pip"): + cand = _candidate_line_for_remaining_install(raw, pypi_versions) + if not cand: + skipped.append(normalize_pkg_line(raw)) + continue + name = parse_name(cand) + if name in current_names: + continue + wanted.append(cand) + + wanted = list(dict.fromkeys(wanted)) + skipped = list(dict.fromkeys(skipped)) + + write_text(lock_dir / ".tmp-full-remaining-install.txt", "\n".join(wanted) + ("\n" if wanted else "")) + write_text(lock_dir / ".tmp-full-remaining-skipped.txt", "\n".join(skipped) + ("\n" if skipped else "")) + + if not wanted: + print("[INFO] No additional remaining pip deps to install from full lock.") + return + + print(f"[INFO] Installing {len(wanted)} remaining pip deps from full lock...") + install_requirements_file(lock_dir, msvc_mode, wanted, lock_dir / ".tmp-full-remaining-install.txt") + + +def restore_protected_from_lock(lock_dir: Path, msvc_mode: str) -> None: + full_lock = pip_lock_filename(lock_dir) + if not full_lock.exists(): + print("[WARN] No full pip lock found; cannot restore protected packages.") + return + + locked: dict[str, str] = {} + for raw in normalize_lines(read_text(full_lock), kind="pip"): + line = normalize_pkg_line(raw) + name = parse_name(line) + if name in PROTECTED_NAMES: + locked[name] = line + + build_plan = load_build_plan(lock_dir) + locked["numpy"] = build_plan.get("numpy_stable") or locked.get("numpy") or DEFAULT_NUMPY + + torch_lines = build_plan.get("torch_preinstall") or [] + for tl in torch_lines: + locked[parse_name(tl)] = tl + + current = {parse_name(x): x for x in normalized_current_pip_lines()} + current_direct = installed_direct_url_map() + + restore_specs: list[str] = [] + + for name, spec in locked.items(): + cur = current.get(name, "") + if spec and cur != spec and " @ file:///" not in spec: + restore_specs.append(spec) + + for name, git_spec in PROTECTED_GIT_PACKAGES.items(): + cur_direct = current_direct.get(name, "") + if not git_requirement_matches(cur_direct, git_spec): + restore_specs.append(git_spec) + + restore_specs = list(dict.fromkeys(restore_specs)) + + if not restore_specs: + print("[INFO] Protected packages already aligned with lock.") + return + + print( + "[INFO] Restoring protected packages to locked versions: " + + ", ".join(parse_name(x) for x in restore_specs) + ) + + torch_specs = [x for x in restore_specs if parse_name(x) in {"torch", "torchvision", "torchaudio"}] + other_specs = [x for x in restore_specs if parse_name(x) not in {"torch", "torchvision", "torchaudio"}] + + if torch_specs: + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + *torch_specs, + "--index-url", + TORCH_INDEX, + ], + msvc_mode, + ) + + if other_specs: + install_requirements_file(lock_dir, msvc_mode, other_specs, lock_dir / ".tmp-protected-restore.txt") + +def print_strict_alignment_status(lock_dir: Path) -> None: + plan = load_build_plan(lock_dir) + pip_current = normalized_current_pip_lines() + pip_set = {parse_name(x): x for x in pip_current} + pip_direct = installed_direct_url_map() + + strict_names = [ + "numpy", + "torch", + "torchvision", + "torchaudio", + "torch-scatter", + "tinycudann", + "tiny-cuda-nn", + "nerfstudio", + "nerfacc", + "gsplat", + "viser", + "huggingface-hub", + "bitsandbytes", + "tyro", + "pycolmap", + "protobuf", + "matplotlib", + ] + + print("[INFO] Strict alignment status:") + print(f" [TARGET NUMPY] {plan.get('numpy_stable', DEFAULT_NUMPY)}") + + for name in strict_names: + if name == "pycolmap": + cur = pip_direct.get("pycolmap", "") or pip_set.get("pycolmap", "") + if git_requirement_matches(cur, PYCOLMAP_GIT): + print(f" [OK] pycolmap @ {PYCOLMAP_GIT}") + elif cur: + print(f" [DRIFT] {cur}") + else: + print(" [MISS] pycolmap") + continue + + if name in {"tinycudann", "tiny-cuda-nn"}: + cur = pip_direct.get("tinycudann", "") or pip_direct.get("tiny-cuda-nn", "") or pip_set.get("tinycudann", "") + if git_requirement_matches(cur, TCNN_GIT): + print(f" [OK] tinycudann @ {TCNN_GIT}") + elif cur: + print(f" [DRIFT] {cur}") + else: + print(f" [MISS] {name}") + continue + + if name in pip_set: + print(f" [OK] {pip_set[name]}") + else: + print(f" [MISS] {name}") + + print(f" [RUNTIME tinycudann] {'OK' if detect_tcnn_runtime() else 'MISSING'}") + +def repin(lock_dir: Path, *, skip_conda: bool = False, force_conda: bool = False, conda_exe: Optional[str] = None, msvc_mode: str = "") -> int: + conda_lock = find_conda_lock(lock_dir) + if conda_lock and not skip_conda: + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + print(f"[DEBUG] Using conda executable: {conda_exe}") + print(f"[DEBUG] CONDA_PREFIX={os.environ.get('CONDA_PREFIX')}") + if force_conda: + if conda_exe and os.environ.get("CONDA_PREFIX"): + cmd = choose_conda_restore_cmd(conda_exe, conda_lock) + print(f"[INFO] Re-applying exact conda lock with verbose restore from: {conda_lock}") + print_run(cmd) + elif conda_exe: + print("[WARN] Conda lock found, but current shell is not an active conda env; skipping conda repin.") + else: + print("[WARN] Conda lock found, but conda is not on PATH; skipping conda repin.") + else: + print("[INFO] Existing-env repin defaults to pip-layer replay only.") + print("[INFO] Use --force-conda if you explicitly want a full verbose conda restore in-place.") + elif skip_conda: + print("[INFO] Skipping conda layer by request.") + + replay_lock = replay_pip_filename(lock_dir) + pip_lock = replay_lock if replay_lock.exists() else pip_lock_filename(lock_dir) + if not pip_lock.exists(): + print("[WARN] No pip lock found.") + return 0 + + installer = load_installer_selection(lock_dir) + effective_msvc = str(installer.get("preferred_msvc") or msvc_mode or os.environ.get("PREFERRED_MSVC") or "").strip() + plan = load_build_plan(lock_dir) + numpy_spec = plan.get("numpy_stable") or DEFAULT_NUMPY + tcnn_arch = str((plan.get("tinycudann") or {}).get("cuda_arch", "")).strip() or current_tcnn_arch() + torch_lines, pyg_lines, tcnn_line, bulk, deferred, av_lines = split_pip_lock(read_text(pip_lock), lock_dir) + + if pip_lock.name == "pip-freeze-replay.txt": + print(f"[INFO] Re-applying replay-safe pip lock from: {pip_lock}") + else: + print(f"[INFO] Re-applying exact pip lock from: {pip_lock}") + + state: dict = {} + install_packaging_base(lock_dir, effective_msvc) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="bootstrap") + install_torch_preinstall(lock_dir, effective_msvc, torch_lines, numpy_spec, state) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-torch") + install_pyg_wheels(lock_dir, effective_msvc, torch_lines, pyg_lines) + install_tcnn(lock_dir, effective_msvc, tcnn_line, tcnn_arch) + install_requirements_file(lock_dir, effective_msvc, bulk, lock_dir / ".tmp-bulk-install.txt") + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-bulk") + install_remaining_from_full_lock(lock_dir, effective_msvc) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-full-remaining") + install_deferred(lock_dir, effective_msvc, deferred) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-deferred") + install_av(lock_dir, effective_msvc, av_lines) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-av") + restore_protected_from_lock(lock_dir, effective_msvc) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-protected-restore") + print_strict_alignment_status(lock_dir) + return 0 + + +def create_env(lock_dir: Path, *, env_name: str, conda_exe: Optional[str] = None, force_repin: bool = True, msvc_mode: str = "") -> int: + conda_lock = find_conda_lock(lock_dir) + if not conda_lock: + print("[ERROR] No conda explicit lock found.") + return 1 + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + if not conda_exe: + print("[ERROR] Could not locate conda executable.") + return 1 + print(f"[INFO] Creating new env from lock: {env_name}") + print_run([conda_exe, "create", "--solver=libmamba", "--yes", "--name", env_name, "--file", str(conda_lock), "--verbose"]) + if force_repin: + print(f"[INFO] Running staged pip replay into env: {env_name}") + cmd = [conda_exe, "run", "-n", env_name, "python", str(ROOT / "deps_lock.py"), "--lock-dir", str(lock_dir), "--conda-exe", conda_exe] + if msvc_mode: + cmd.extend(["--msvc-mode", msvc_mode]) + cmd.extend(["repin", "--skip-conda"]) + print_run(cmd) + return 0 + +def apply_extra_patches(root_dir: Path) -> None: + patch_root = root_dir / "Extra-Methods-Patches" + + if not patch_root.exists(): + print("[INFO] No Extra-Methods-Patches directory found; skipping.") + return + + print("[INFO] Applying external patch tree...") + + for src in patch_root.rglob("*"): + if src.is_dir(): + continue + + rel = src.relative_to(patch_root) + dst = root_dir / rel + + if not dst.exists(): + print(f"[WARN] Target missing for patch: {dst}") + continue + + backup = dst.with_suffix(dst.suffix + ".orig") + if not backup.exists(): + shutil.copy2(dst, backup) + + shutil.copy2(src, dst) + print(f"[PATCH] {rel}") + +def install_editable(project_dir: Path, lock_dir: Path, msvc_mode: str) -> int: + installer = load_installer_selection(lock_dir) + effective_msvc = str(installer.get("preferred_msvc") or msvc_mode or os.environ.get("PREFERRED_MSVC") or "").strip() + print(f"[INFO] Installing editable project without dependency mutation: {project_dir}") + print_run_bootstrapped( + lock_dir, + [sys.executable, "-m", "pip", "install", *PIP_VERBOSE_ARGS, "--no-deps", "-e", str(project_dir)], + effective_msvc, + ) + return 0 + + +def build_parser() -> argparse.ArgumentParser: + p = argparse.ArgumentParser(description="Snapshot and restore an exact conda/pip dependency baseline with shell-level MSVC/CUDA bootstrap.") + p.add_argument("--lock-dir", default=str(DEFAULT_LOCK_DIR), help="Lock directory") + p.add_argument("--conda-exe", default=os.environ.get("CONDA_EXE"), help="Explicit conda executable (portable override)") + p.add_argument("--msvc-mode", default="", choices=["", "auto", "14.38", "14", "system"], help="Preferred MSVC toolset mode for builds (optional)") + sub = p.add_subparsers(dest="cmd", required=True) + sub.add_parser("export", help="Snapshot current active env") + sub.add_parser("check", help="Compare current env with lock") + rep = sub.add_parser("repin", help="Replay lock into current active env") + rep.add_argument("--skip-conda", action="store_true", help="Skip conda explicit lock replay") + rep.add_argument("--force-conda", action="store_true", help="Force a full verbose conda in-place restore before staged pip replay") + cre = sub.add_parser("create", help="Create a new conda env from explicit lock, then replay pip layer") + cre.add_argument("--env-name", required=True, help="Target conda env name") + cre.add_argument("--no-repin", action="store_true", help="Create env from conda explicit lock only, skip pip staged replay") + ed = sub.add_parser("editable", help="Install repo editable without dependency resolution") + ed.add_argument("project_dir", nargs="?", default=".") + return p + + +def main(argv: Optional[list[str]] = None) -> int: + args = build_parser().parse_args(argv) + lock_dir = Path(args.lock_dir).resolve() + if getattr(args, "msvc_mode", ""): + os.environ["PREFERRED_MSVC"] = args.msvc_mode + print(f"[INFO] Preferred MSVC mode: {args.msvc_mode}") + try: + if args.cmd == "export": + return export_locks(lock_dir, conda_exe=args.conda_exe, msvc_mode=args.msvc_mode) + if args.cmd == "check": + return check_locks(lock_dir, conda_exe=args.conda_exe) + if args.cmd == "repin": + return repin(lock_dir, skip_conda=args.skip_conda, force_conda=args.force_conda, conda_exe=args.conda_exe, msvc_mode=args.msvc_mode) + if args.cmd == "create": + return create_env(lock_dir, env_name=args.env_name, conda_exe=args.conda_exe, force_repin=not args.no_repin, msvc_mode=args.msvc_mode) + if args.cmd == "editable": + return install_editable(Path(args.project_dir).resolve(), lock_dir, args.msvc_mode) + raise AssertionError(args.cmd) + except subprocess.CalledProcessError as e: + cmd = e.cmd if isinstance(e.cmd, str) else " ".join(str(x) for x in e.cmd) + print(f"[ERROR] Command failed with exit code {e.returncode}: {cmd}") + return e.returncode or 1 + except RuntimeError as e: + print(f"[ERROR] {e}") + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) \ No newline at end of file diff --git a/docker_notes.md b/docker_notes.md new file mode 100644 index 0000000000..6d2e35c47e --- /dev/null +++ b/docker_notes.md @@ -0,0 +1,37 @@ +# Docker fix notes for `nerfstudio_custom` + +The current failing layer groups several risky operations into a single `RUN`, so GitHub Actions only reports the full shell line and exit code. Split the layer so the failing sub-step becomes visible. + +Recommended replacement pattern: + +```dockerfile +RUN python3.10 -m pip install --no-cache-dir --upgrade pip 'setuptools<70.0.0' +RUN python3.10 -m pip install --no-cache-dir torch==2.1.2+cu118 torchvision==0.16.2+cu118 'numpy<2.0.0' \ + --extra-index-url https://download.pytorch.org/whl/cu118 +RUN git clone --branch master --recursive https://github.com/cvg/Hierarchical-Localization.git /opt/hloc \ + && cd /opt/hloc \ + && git checkout v1.4 \ + && python3.10 -m pip install --no-cache-dir . +RUN TCNN_CUDA_ARCHITECTURES="${CUDA_ARCHITECTURES}" python3.10 -m pip install --no-cache-dir -v \ + "git+https://github.com/NVlabs/tiny-cuda-nn.git@b3473c81396fe927293bdfd5a6be32df8769927c#subdirectory=bindings/torch" +RUN python3.10 -m pip install --no-cache-dir pycolmap==0.6.1 pyceres==2.1 omegaconf==2.3.0 +``` + +Two practical changes matter here: + +1. Use `python3.10 -m pip` everywhere instead of mixing `pip` and `python3.10 -m pip`. +2. Add `-v` to the tiny-cuda-nn install, because that is one of the most common native-build failure points in CUDA Docker builds. + +If the split build still fails, the log will finally tell you whether the culprit is: +- `hloc` +- `tiny-cuda-nn` +- `pycolmap` +- `pyceres` + +Also consider lowering the architecture list while debugging, for example: + +```dockerfile +ARG CUDA_ARCHITECTURES="86" +``` + +That reduces compile work significantly while you stabilize CI. diff --git a/doctor.bat b/doctor.bat new file mode 100644 index 0000000000..1dfdd5f937 --- /dev/null +++ b/doctor.bat @@ -0,0 +1,40 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion +cd /d "%~dp0" + +set "ROOT=%CD%" +set "DOCTOR_PY=%ROOT%\doctor.py" +set "PORTABLE_ENV_BAT=%ROOT%\portable_env.bat" +set "PYTHON_EXE=" + +echo ========================================== +echo Nerfstudio Doctor +echo ========================================== + +if exist "%PORTABLE_ENV_BAT%" ( + echo [INFO] Activating portable conda... + call "%PORTABLE_ENV_BAT%" + if errorlevel 1 echo [WARN] Portable activation failed. Trying current python. +) + +if not exist "%DOCTOR_PY%" ( + echo [ERROR] Missing doctor script: + echo %DOCTOR_PY% + exit /b 1 +) + +if not defined PYTHON_EXE if exist "%ROOT%\.conda\python.exe" set "PYTHON_EXE=%ROOT%\.conda\python.exe" +if not defined PYTHON_EXE if defined CONDA_PREFIX if exist "%CONDA_PREFIX%\python.exe" set "PYTHON_EXE=%CONDA_PREFIX%\python.exe" +if not defined PYTHON_EXE set "PYTHON_EXE=python" + +echo [INFO] Running diagnostics with: %PYTHON_EXE% +"%PYTHON_EXE%" "%DOCTOR_PY%" %* +if errorlevel 1 ( + echo. + echo [FAIL] Doctor detected problems + exit /b 1 +) + +echo. +echo [OK] Environment is healthy +exit /b 0 diff --git a/dump_tetranerf_config.py b/dump_tetranerf_config.py new file mode 100644 index 0000000000..39b0a1945c --- /dev/null +++ b/dump_tetranerf_config.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +from dataclasses import fields, is_dataclass +from typing import Any + +from tetranerf.nerfstudio.registration import tetranerf + + +def walk(name: str, obj: Any, depth: int = 0, max_depth: int = 8) -> None: + indent = " " * depth + print(f"{indent}{name}: {type(obj).__name__}") + + if depth >= max_depth: + return + + if is_dataclass(obj): + for f in fields(obj): + try: + value = getattr(obj, f.name) + except Exception as exc: + print(f"{indent} {f.name}: ") + continue + walk(f.name, value, depth + 1, max_depth) + + +if __name__ == "__main__": + print("=== Tetra-NeRF TrainerConfig tree ===") + walk("config", tetranerf.config) \ No newline at end of file diff --git a/extras_portable_manager.bat b/extras_portable_manager.bat new file mode 100644 index 0000000000..e75e6e1ac7 --- /dev/null +++ b/extras_portable_manager.bat @@ -0,0 +1,646 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion +cd /d "%~dp0" + +set "ROOT_DIR=%CD%" +set "PORTABLE_ENV_BAT=%ROOT_DIR%\portable_env.bat" +set "LOCK_DIR=%ROOT_DIR%\deps-lock" +set "PY_SCRIPT=%ROOT_DIR%\deps_lock.py" +set "PATCH_ROOT=%ROOT_DIR%\Extra-Methods-Patches" +set "CORE_OVERRIDES_JSON=%LOCK_DIR%\nerfstudio-core-overrides.json" +set "METHODS_PROTECTED_JSON=%LOCK_DIR%\nerfstudio-methods-protected.json" + +set "TARGET_ENV=%~1" +if not defined TARGET_ENV set "TARGET_ENV=nerfstudio-portable" + +if not exist "%PY_SCRIPT%" ( + echo [ERROR] Missing deps_lock.py + exit /b 1 +) + +if not exist "%PORTABLE_ENV_BAT%" ( + echo [ERROR] Missing portable helper: %PORTABLE_ENV_BAT% + exit /b 1 +) + +call "%PORTABLE_ENV_BAT%" +if errorlevel 1 exit /b %errorlevel% + +if not defined PORTABLE_CONDA_ROOT if exist "%ROOT_DIR%\.conda\Scripts\conda.exe" set "PORTABLE_CONDA_ROOT=%ROOT_DIR%\.conda" +if not defined PORTABLE_CONDA_ROOT ( + echo [ERROR] PORTABLE_CONDA_ROOT not available. + exit /b 1 +) + +set "CONDA_EXE=%PORTABLE_CONDA_ROOT%\Scripts\conda.exe" +set "CONDA_BAT=%PORTABLE_CONDA_ROOT%\condabin\conda.bat" + +if not exist "%CONDA_EXE%" ( + echo [ERROR] Missing conda.exe: %CONDA_EXE% + exit /b 1 +) +if not exist "%CONDA_BAT%" ( + echo [ERROR] Missing conda.bat: %CONDA_BAT% + exit /b 1 +) +REM Nerfstudio Custom - pinned extras / methods installer +call :clear_rocm_env +call "%CONDA_BAT%" activate "%TARGET_ENV%" +if errorlevel 1 ( + echo [ERROR] Failed to activate env: %TARGET_ENV% + exit /b %errorlevel% +) + +echo [INFO] Active env: %TARGET_ENV% +where python +python --version + +set "PIN_TORCH=torch==2.1.2+cu118" +set "PIN_TORCHVISION=torchvision==0.16.2+cu118" +set "PIN_TORCHAUDIO=torchaudio==2.1.2+cu118" +set "PIN_NUMPY=numpy==1.26.4" +set "PIN_NERFSTUDIO=nerfstudio==1.0.3" +set "PIN_TYRO=tyro==0.8.12" + +set "PIN_PYCOLMAP_RMBRUALLA=git+https://github.com/rmbrualla/pycolmap.git" +set "PIN_TCNN_GIT=git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch" + +set "PIN_VISER=viser==0.1.26" +set "PIN_NERFACC=nerfacc==0.5.2" +set "PIN_GSPLAT=gsplat==1.5.3" +set "PIN_HF_HUB=huggingface-hub==1.9.0" +set "PIN_BITSANDBYTES=bitsandbytes==0.49.2" + +if not exist "%LOCK_DIR%" mkdir "%LOCK_DIR%" 2>nul + +call :clear_rocm_env +if errorlevel 1 exit /b %errorlevel% + +echo. +echo ====================================================== +echo Extras target env: %TARGET_ENV% +echo Conda exe: %CONDA_EXE% +echo Python script: %PY_SCRIPT% +echo ====================================================== +echo. +echo Available extras: +echo 1. Install / repair pinned Nerfstudio core packages +echo 2. Install Zip-NeRF ^(Windows-patched^) +echo 3. Install rmbrualla pycolmap only +echo 4. Install torch-scatter only +echo 5. Run ns-install-cli only +echo 6. Re-pin current target env only +echo 7. Install support packages ^(nerfacc, gsplat, viser, hf-hub, bitsandbytes, tyro^) +echo 8. Full recommended extras bootstrap ^(core + support + Zip-NeRF^) +echo 9. Install Tetra-NeRF (Windows-patched) +echo 10. Install manifest-managed core overrides +echo 11. Install manifest-managed protected methods +echo 12. Full manifest-driven extras bootstrap + echo 13. Install Splatfacto-W (Windows-patched) +echo. +set /p "CHOICE=Enter choice [1-13]: " + +if "%CHOICE%"=="1" goto :do_core +if "%CHOICE%"=="2" goto :do_zipnerf +if "%CHOICE%"=="3" goto :do_pycolmap +if "%CHOICE%"=="4" goto :do_torchscatter +if "%CHOICE%"=="5" goto :do_ns_cli +if "%CHOICE%"=="6" goto :do_repin +if "%CHOICE%"=="7" goto :do_support +if "%CHOICE%"=="8" goto :full_bootstrap +if "%CHOICE%"=="9" goto +:do_splatfactow +call :install_splatfactow +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_tetra_nerf +if "%CHOICE%"=="10" goto :do_core_overrides_manifest +if "%CHOICE%"=="11" goto :do_methods_manifest +if "%CHOICE%"=="12" goto :do_full_manifest +if "%CHOICE%"=="13" goto :do_splatfactow +echo [ERROR] Invalid choice. +exit /b 1 + +:full_bootstrap +echo. +echo [STEP] Ensuring support packages used by extra methods... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps %PIN_NERFACC% %PIN_GSPLAT% %PIN_VISER% %PIN_HF_HUB% %PIN_BITSANDBYTES% %PIN_TYRO% +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Ensuring pinned Nerfstudio core packages... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps %PIN_NERFSTUDIO% +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Installing rmbrualla pycolmap... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps --no-build-isolation git+https://github.com/rmbrualla/pycolmap.git +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Installing torch-scatter... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps torch-scatter==2.1.2+pt21cu118 -f https://data.pyg.org/whl/torch-2.1.0+cu118.html +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Installing Zip-NeRF... +call :install_zipnerf +if errorlevel 1 exit /b %errorlevel% + +call :run_ns_install_cli +if errorlevel 1 exit /b %errorlevel% + +call :repin_target_env +exit /b %errorlevel% + +:do_full +call :ensure_support_packages +if errorlevel 1 exit /b %errorlevel% +call :install_zipnerf +if errorlevel 1 exit /b %errorlevel% +goto +:do_core_overrides_manifest +call :install_core_overrides_from_manifest +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_methods_manifest +call :install_manifest_methods +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_full_manifest +echo. +echo [STEP] Ensuring core stack and support packages... +call :ensure_core_stack +if errorlevel 1 exit /b %errorlevel% +call :ensure_support_packages +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Installing manifest-managed core overrides... +call :install_core_overrides_from_manifest +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Installing torch-scatter... +call :install_torch_scatter +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Installing manifest-managed protected methods... +call :install_manifest_methods +if errorlevel 1 exit /b %errorlevel% + +call :run_ns_install_cli +if errorlevel 1 exit /b %errorlevel% +call :repin_target_env +exit /b %errorlevel% +:success + +:do_core +call :ensure_core_stack +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_support +call :ensure_support_packages +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_zipnerf +call :install_zipnerf +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_pycolmap +call :install_rmbrualla_pycolmap +if errorlevel 1 exit /b %errorlevel% +call :ns_register_and_repin +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_torchscatter +call :install_torch_scatter +if errorlevel 1 exit /b %errorlevel% +call :ns_register_and_repin +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_ns_cli +call :run_in_env python -m ns_install_cli +if errorlevel 1 ( + call :run_in_env ns-install-cli + if errorlevel 1 exit /b %errorlevel% +) +goto :success + +:do_repin +call :repin_target +if errorlevel 1 exit /b %errorlevel% +goto :success + +:success +echo. +echo [OK] Extras flow completed successfully. +exit /b 0 + +:ensure_core_stack +echo. +echo [STEP] Ensuring pinned Nerfstudio core stack... +call :clear_rocm_env +call :run_in_env python -m pip install --upgrade pip setuptools^<81 wheel +if errorlevel 1 exit /b %errorlevel% +call :run_in_env python -m pip install --upgrade --force-reinstall %PIN_NUMPY% +if errorlevel 1 exit /b %errorlevel% +call :run_in_env python -m pip install --upgrade --force-reinstall %PIN_TORCH% %PIN_TORCHVISION% %PIN_TORCHAUDIO% --index-url https://download.pytorch.org/whl/cu118 +if errorlevel 1 exit /b %errorlevel% +call :run_in_env python -m pip install --upgrade --force-reinstall %PIN_NUMPY% +if errorlevel 1 exit /b %errorlevel% +call :run_in_env python -m pip install --upgrade --force-reinstall %PIN_NERFSTUDIO% %PIN_TYRO% +if errorlevel 1 exit /b %errorlevel% +call :set_cuda_arch_env +call :run_in_env python -m pip install -v --upgrade --force-reinstall --no-build-isolation --no-cache-dir %PIN_TCNN_GIT% +if errorlevel 1 exit /b %errorlevel% +call :ns_register_and_repin +exit /b %errorlevel% + +:set_cuda_env +if not defined CUDA_HOME if exist "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8" set "CUDA_HOME=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8" +if not defined CUDA_PATH if defined CUDA_HOME set "CUDA_PATH=%CUDA_HOME%" +if defined CUDA_HOME set "PATH=%CUDA_HOME%\bin;%CUDA_HOME%\libnvvp;%PATH%" +if not defined TCNN_CUDA_ARCHITECTURES set "TCNN_CUDA_ARCHITECTURES=86" +if not defined TORCH_CUDA_ARCH_LIST set "TORCH_CUDA_ARCH_LIST=8.6" +if not defined MAX_JOBS set "MAX_JOBS=1" +exit /b 0 + +:do_tetra_nerf +call +:install_splatfactow +echo. +echo [STEP] Installing Splatfacto-W with Windows-safe patches... +call :clear_rocm_env +if errorlevel 1 exit /b %errorlevel% + +if not exist "%ROOT_DIR%\splatfacto-w" ( + echo [INFO] Cloning splatfacto-w... + call :run_in_env git clone https://github.com/KevinXu02/splatfacto-w "%ROOT_DIR%\splatfacto-w" + if errorlevel 1 exit /b %errorlevel% +) + +if exist "%PATCH_ROOT%\splatfacto-w" ( + call :apply_patch_tree "%PATCH_ROOT%\splatfacto-w" "%ROOT_DIR%\splatfacto-w" + if errorlevel 1 exit /b %errorlevel% +) else ( + echo [INFO] No patch tree found for splatfacto-w at %PATCH_ROOT%\splatfacto-w +) + +call :run_in_env cmd /d /s /c "cd /d "%ROOT_DIR%\splatfacto-w" && python -m pip install -e . --no-deps" +if errorlevel 1 exit /b %errorlevel% + +call :ns_register_and_repin +exit /b %errorlevel% + +:install_tetra_nerf +if errorlevel 1 exit /b %errorlevel% +goto :success + +:install_tetra_nerf +echo. +echo [STEP] Installing Tetra-NeRF with Windows-safe patches... +call :clear_rocm_env +if errorlevel 1 exit /b %errorlevel% + +if not exist "%ROOT_DIR%\tetra-nerf" ( + echo [INFO] Cloning tetra-nerf... + call :run_in_env git clone https://github.com/jkulhanek/tetra-nerf.git + if errorlevel 1 exit /b %errorlevel% +) + +call :apply_patch_file "%PATCH_ROOT%\tetra-nerf\CMakeLists.txt" "%ROOT_DIR%\tetra-nerf\CMakeLists.txt" +if errorlevel 1 exit /b %errorlevel% + +call :apply_patch_file "%PATCH_ROOT%\tetra-nerf\cmake\FindTorch.cmake" "%ROOT_DIR%\tetra-nerf\cmake\FindTorch.cmake" +if errorlevel 1 exit /b %errorlevel% + +call :apply_patch_file "%PATCH_ROOT%\tetra-nerf\cmake\FindCUDA.cmake" "%ROOT_DIR%\tetra-nerf\cmake\FindCUDA.cmake" +if errorlevel 1 exit /b %errorlevel% + +call :apply_patch_file "%PATCH_ROOT%\tetra-nerf\src\tetrahedra_tracer.h" "%ROOT_DIR%\tetra-nerf\src\tetrahedra_tracer.h" +if errorlevel 1 exit /b %errorlevel% + +call :apply_patch_file "%PATCH_ROOT%\tetra-nerf\src\utils\vec_math.h" "%ROOT_DIR%\tetra-nerf\src\utils\vec_math.h" +if errorlevel 1 exit /b %errorlevel% + +for %%I in ("C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8") do set "CUDA118_SHORT=%%~sI" +for %%I in ("C:\Program Files\NVIDIA Corporation\OptiX SDK 9.1.0") do set "OPTIX_SHORT=%%~sI" + +set "CUDA118_CMAKE=%CUDA118_SHORT:\=/%" +set "OPTIX_CMAKE=%OPTIX_SHORT:\=/%" +set "TETRA_SCRIPT=%TEMP%\tetra_build_%RANDOM%.cmd" + +> "%TETRA_SCRIPT%" echo @echo off +>> "%TETRA_SCRIPT%" echo setlocal +>> "%TETRA_SCRIPT%" echo cd /d "%ROOT_DIR%\tetra-nerf" +>> "%TETRA_SCRIPT%" echo if exist build-cu118 rmdir /S /Q build-cu118 +>> "%TETRA_SCRIPT%" echo set "PATH=%CUDA118_SHORT%\bin;%%PATH%%" +>> "%TETRA_SCRIPT%" echo cmake -S . -B build-cu118 -T cuda="%CUDA118_CMAKE%" -DCUDA_TOOLKIT_ROOT_DIR="%CUDA118_CMAKE%" -DOptiX_INSTALL_DIR="%OPTIX_CMAKE%" +>> "%TETRA_SCRIPT%" echo if errorlevel 1 exit /b 1 +>> "%TETRA_SCRIPT%" echo cmake --build build-cu118 --config Release +>> "%TETRA_SCRIPT%" echo if errorlevel 1 exit /b 1 +>> "%TETRA_SCRIPT%" echo python -m pip install -e . --no-deps + +call :run_in_env cmd /d /s /c ""%TETRA_SCRIPT%"" +set "TETRA_RC=%errorlevel%" +del /Q "%TETRA_SCRIPT%" >nul 2>nul + +if not "%TETRA_RC%"=="0" exit /b %TETRA_RC% + +call :ns_register_and_repin +exit /b %errorlevel% + +:install_zipnerf +echo. +echo [STEP] Installing Zip-NeRF with Windows-safe patches... +call :clear_rocm_env +if errorlevel 1 exit /b %errorlevel% + +if not exist "%ROOT_DIR%\zipnerf-pytorch" ( + echo [INFO] Cloning zipnerf-pytorch... + call :run_in_env git clone https://github.com/SuLvXiangXin/zipnerf-pytorch.git + if errorlevel 1 exit /b %errorlevel% +) + +set "ZIP_PATCH_SRC=%PATCH_ROOT%\zipnerf-pytorch\extensions\cuda\setup.py" +set "ZIP_PATCH_DST=%ROOT_DIR%\zipnerf-pytorch\extensions\cuda\setup.py" + +call :apply_patch_file "%ZIP_PATCH_SRC%" "%ZIP_PATCH_DST%" +if errorlevel 1 exit /b %errorlevel% +call :set_cuda_arch_env +call :set_cuda_env + +echo [INFO] Installing Zip-NeRF CUDA extension... +call :run_in_env cmd /d /s /c "cd /d ""%ROOT_DIR%\zipnerf-pytorch\extensions\cuda"" && python -m pip install --no-build-isolation ." +if errorlevel 1 ( + echo [WARN] pip install . failed, trying setup.py install fallback... + call :set_cuda_env + call :run_in_env cmd /d /s /c "cd /d ""%ROOT_DIR%\zipnerf-pytorch\extensions\cuda"" && python setup.py install" + if errorlevel 1 exit /b %errorlevel% +) + +echo [INFO] Installing Zip-NeRF editable package... +call :run_in_env cmd /d /s /c "cd /d ""%ROOT_DIR%\zipnerf-pytorch"" && python -m pip install -e . --no-deps" +if errorlevel 1 exit /b %errorlevel% + +call :run_in_env python -m pip install --upgrade tyro==0.8.12 +if errorlevel 1 exit /b %errorlevel% + +call :copy_zipnerf_configs +if errorlevel 1 exit /b %errorlevel% + +call :ns_register_and_repin +exit /b %errorlevel% + +:install_rmbrualla_pycolmap +echo [INFO] Installing rmbrualla pycolmap for Zip-NeRF compatibility... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps --no-build-isolation git+https://github.com/rmbrualla/pycolmap.git +exit /b %errorlevel% + +:install_torch_scatter +echo [INFO] Installing torch-scatter compatible with torch 2.1/cu118... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps torch-scatter==2.1.2+pt21cu118 -f https://data.pyg.org/whl/torch-2.1.0+cu118.html +exit /b %errorlevel% + +:copy_zipnerf_configs +set "ZIP_CFG_SRC=%ROOT_DIR%\zipnerf-pytorch\zipnerf_ns\config" +set "ZIP_CFG_DST=" +for /f "usebackq delims=" %%I in (`call "%CONDA_EXE%" run -n "%TARGET_ENV%" python -c "import pathlib, nerfstudio; print(pathlib.Path(nerfstudio.__file__).resolve().parent / 'configs')"` ) do set "ZIP_CFG_DST=%%I" +if not defined ZIP_CFG_DST ( + echo [WARN] Could not resolve nerfstudio config path automatically. Skipping config copy. + exit /b 0 +) +if exist "%ZIP_CFG_SRC%" ( + echo [INFO] Copying Zip-NeRF config files into nerfstudio config dir... + if not exist "%ZIP_CFG_DST%" mkdir "%ZIP_CFG_DST%" 2>nul + xcopy /E /Y /I "%ZIP_CFG_SRC%\*" "%ZIP_CFG_DST%\" >nul + exit /b 0 +) +echo [WARN] Zip-NeRF config source not found, skipping copy: %ZIP_CFG_SRC% +exit /b 0 + +:ns_register_and_repin +echo [INFO] Running ns-install-cli to register plugins... +call :run_in_env ns-install-cli +if errorlevel 1 ( + call :run_in_env python -m nerfstudio.scripts.completions.install + if errorlevel 1 exit /b %errorlevel% +) +call :repin_target +exit /b %errorlevel% + +:repin_target +echo [INFO] Re-applying protected pinned stack after extra installation... +call :clear_rocm_env +call :run_in_env python "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" repin --skip-conda +exit /b %errorlevel% + +:set_cuda_arch_env +if not defined TCNN_CUDA_ARCHITECTURES set "TCNN_CUDA_ARCHITECTURES=86" +if not defined TORCH_CUDA_ARCH_LIST set "TORCH_CUDA_ARCH_LIST=8.6" +if not defined MAX_JOBS set "MAX_JOBS=1" +exit /b 0 + +:ensure_support_packages +echo. +echo [STEP] Ensuring support packages used by extra methods... +call :clear_rocm_env + +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps %PIN_TYRO% %PIN_NERFACC% %PIN_VISER% %PIN_HF_HUB% %PIN_BITSANDBYTES% +if errorlevel 1 exit /b %errorlevel% + +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps %PIN_GSPLAT% +if errorlevel 1 exit /b %errorlevel% + +call :run_in_env python -c "import torch; print(torch.__version__); import gsplat; from gsplat._torch_impl import quat_to_rotmat; print('gsplat OK')" +if errorlevel 1 exit /b %errorlevel% + +call :ns_register_and_repin +exit /b %errorlevel% + +:run_in_env +call :clear_rocm_env +echo [RUN] %* +call "%CONDA_EXE%" run -n "%TARGET_ENV%" --no-capture-output %* +exit /b %errorlevel% + +:repin_target_env +echo. +echo [STEP] Re-pinning target env after extras... +call "%CONDA_BAT%" activate "%TARGET_ENV%" +if errorlevel 1 exit /b %errorlevel% +python "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" repin --skip-conda +set "_REP_RC=%errorlevel%" +call conda deactivate >nul 2>nul +exit /b %_REP_RC% + +:run_ns_install_cli +echo. +echo [STEP] Running ns-install-cli... +call "%CONDA_BAT%" activate "%TARGET_ENV%" +if errorlevel 1 exit /b %errorlevel% +where ns-install-cli >nul 2>nul +if errorlevel 1 ( + python -m ns.install_cli +) else ( + ns-install-cli +) +set "_NSCLI_RC=%errorlevel%" +call conda deactivate >nul 2>nul +exit /b %_NSCLI_RC% + + +:install_core_overrides_from_manifest +if not exist "%CORE_OVERRIDES_JSON%" ( + echo [WARN] Core overrides manifest not found: %CORE_OVERRIDES_JSON% + exit /b 0 +) +for /f "usebackq delims=" %%I in (`call "%CONDA_EXE%" run -n "%TARGET_ENV%" python -c "import json, pathlib; p=pathlib.Path(r'%CORE_OVERRIDES_JSON%'); data=json.loads(p.read_text(encoding='utf-8')); items=data.get('core_overrides', {}); [print(v.get('install_ref','')) for k,v in items.items() if v.get('install_ref')]"`) do ( + echo [INFO] Installing core override: %%I + call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps --no-build-isolation %%I + if errorlevel 1 exit /b %errorlevel% +) +exit /b 0 + +:install_manifest_methods +if not exist "%METHODS_PROTECTED_JSON%" ( + echo [WARN] Methods manifest not found: %METHODS_PROTECTED_JSON% + exit /b 0 +) +for /f "usebackq tokens=1,2,3 delims=|" %%A in (`call "%CONDA_EXE%" run -n "%TARGET_ENV%" python -c "import json, pathlib; p=pathlib.Path(r'%METHODS_PROTECTED_JSON%'); data=json.loads(p.read_text(encoding='utf-8')); items=data.get('protected_methods', {}); [print(f'{k}|{v.get('install_ref','')}|{v.get('patch_rel','')}') for k,v in items.items() if v.get('install_ref')]"`) do ( + call :install_one_manifest_method "%%~A" "%%~B" "%%~C" + if errorlevel 1 exit /b %errorlevel% +) +exit /b 0 + +:install_one_manifest_method +set "METHOD_KEY=%~1" +set "METHOD_REF=%~2" +set "METHOD_PATCH_REL=%~3" +if /I "%METHOD_KEY%"=="zipnerf-pytorch" ( + call :install_zipnerf + exit /b %errorlevel% +) +if /I "%METHOD_KEY%"=="tetra-nerf" ( + call :install_tetra_nerf + exit /b %errorlevel% +) +if /I "%METHOD_KEY%"=="splatfacto-w" ( + call :install_splatfactow + exit /b %errorlevel% +) +call :install_generic_manifest_method "%METHOD_KEY%" "%METHOD_REF%" "%METHOD_PATCH_REL%" +exit /b %errorlevel% + +:install_generic_manifest_method +set "GEN_METHOD_KEY=%~1" +set "GEN_METHOD_REF=%~2" +set "GEN_METHOD_PATCH_REL=%~3" +if not defined GEN_METHOD_KEY ( + echo [ERROR] Missing generic method key. + exit /b 1 +) +set "GEN_METHOD_DIR=%ROOT_DIR%\%GEN_METHOD_KEY%" +if not exist "%GEN_METHOD_DIR%" ( + echo [INFO] Cloning %GEN_METHOD_KEY%... + call :run_in_env git clone "%GEN_METHOD_REF%" "%GEN_METHOD_DIR%" + if errorlevel 1 exit /b %errorlevel% +) +if defined GEN_METHOD_PATCH_REL ( + if exist "%PATCH_ROOT%\%GEN_METHOD_PATCH_REL%" ( + call :apply_patch_tree "%PATCH_ROOT%\%GEN_METHOD_PATCH_REL%" "%GEN_METHOD_DIR%" + if errorlevel 1 exit /b %errorlevel% + ) else ( + echo [INFO] No patch tree found for %GEN_METHOD_KEY% at %PATCH_ROOT%\%GEN_METHOD_PATCH_REL% + ) +) +call :run_in_env cmd /d /s /c "cd /d \"%GEN_METHOD_DIR%\" && python -m pip install -e . --no-deps" +if errorlevel 1 exit /b %errorlevel% +call :ns_register_and_repin +exit /b %errorlevel% + +:apply_patch_tree +set "PATCH_TREE_SRC=%~1" +set "PATCH_TREE_DST=%~2" +if not exist "%PATCH_TREE_SRC%" ( + echo [WARN] Patch tree missing: %PATCH_TREE_SRC% + exit /b 0 +) +if not exist "%PATCH_TREE_DST%" ( + echo [ERROR] Patch destination root missing: %PATCH_TREE_DST% + exit /b 1 +) +for /r "%PATCH_TREE_SRC%" %%F in (*) do ( + set "SRC_FILE=%%~fF" + set "REL_FILE=!SRC_FILE:%PATCH_TREE_SRC%\=!" + if /I not "%%~xF"==".diff" if /I not "%%~xF"==".patch" if /I not "%%~xF"==".patched" ( + call :apply_patch_file "%%~fF" "%PATCH_TREE_DST%\!REL_FILE!" + if errorlevel 1 exit /b %errorlevel% + ) +) +exit /b 0 + +:apply_patch_file +set "PATCH_SRC=%~1" +set "PATCH_DST=%~2" + +if not defined PATCH_SRC ( + echo [ERROR] Missing patch source path. + exit /b 1 +) +if not defined PATCH_DST ( + echo [ERROR] Missing patch destination path. + exit /b 1 +) + +if not exist "%PATCH_SRC%" ( + echo [ERROR] Patch source not found: %PATCH_SRC% + exit /b 1 +) + +if not exist "%PATCH_DST%" ( + echo [ERROR] Patch target not found: %PATCH_DST% + exit /b 1 +) + +if not exist "%PATCH_DST%.orig" ( + copy /Y "%PATCH_DST%" "%PATCH_DST%.orig" >nul + if errorlevel 1 ( + echo [ERROR] Failed creating backup: %PATCH_DST%.orig + exit /b 1 + ) +) + +copy /Y "%PATCH_SRC%" "%PATCH_DST%" >nul +if errorlevel 1 ( + echo [ERROR] Failed applying patch file. + exit /b 1 +) + +echo [OK] Applied patch: +echo SRC: %PATCH_SRC% +echo DST: %PATCH_DST% +exit /b 0 + +:clear_rocm_env +set "ROCM_HOME=" +set "ROCM_PATH=" +set "HIP_HOME=" +set "HIP_PATH=" +set "HCC_HOME=" +set "HIP_PATH_57=" +set "HIP_DEVICE_LIB_PATH=" +set "PYTORCH_ROCM_ARCH=" +exit /b 0 + + diff --git a/extras_portable_manager.bat.bak b/extras_portable_manager.bat.bak new file mode 100644 index 0000000000..f89c2d5f34 --- /dev/null +++ b/extras_portable_manager.bat.bak @@ -0,0 +1,474 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion +cd /d "%~dp0" + +set "ROOT_DIR=%CD%" +set "PORTABLE_ENV_BAT=%ROOT_DIR%\portable_env.bat" +set "LOCK_DIR=%ROOT_DIR%\deps-lock" +set "PY_SCRIPT=%ROOT_DIR%\deps_lock.py" + +set "TARGET_ENV=%~1" +if not defined TARGET_ENV set "TARGET_ENV=nerfstudio-portable" + +if not exist "%PY_SCRIPT%" ( + echo [ERROR] Missing deps_lock.py + exit /b 1 +) + +if not exist "%PORTABLE_ENV_BAT%" ( + echo [ERROR] Missing portable helper: %PORTABLE_ENV_BAT% + exit /b 1 +) + +call "%PORTABLE_ENV_BAT%" +if errorlevel 1 exit /b %errorlevel% + +if not defined PORTABLE_CONDA_ROOT if exist "%ROOT_DIR%\.conda\Scripts\conda.exe" set "PORTABLE_CONDA_ROOT=%ROOT_DIR%\.conda" +if not defined PORTABLE_CONDA_ROOT ( + echo [ERROR] PORTABLE_CONDA_ROOT not available. + exit /b 1 +) + +set "CONDA_EXE=%PORTABLE_CONDA_ROOT%\Scripts\conda.exe" +set "CONDA_BAT=%PORTABLE_CONDA_ROOT%\condabin\conda.bat" + +if not exist "%CONDA_EXE%" ( + echo [ERROR] Missing conda.exe: %CONDA_EXE% + exit /b 1 +) +if not exist "%CONDA_BAT%" ( + echo [ERROR] Missing conda.bat: %CONDA_BAT% + exit /b 1 +) +REM Nerfstudio Custom - pinned extras / methods installer +call :clear_rocm_env +call "%CONDA_BAT%" activate "%TARGET_ENV%" +if errorlevel 1 ( + echo [ERROR] Failed to activate env: %TARGET_ENV% + exit /b %errorlevel% +) + +echo [INFO] Active env: %TARGET_ENV% +where python +python --version + +set "PIN_TORCH=torch==2.1.2+cu118" +set "PIN_TORCHVISION=torchvision==0.16.2+cu118" +set "PIN_TORCHAUDIO=torchaudio==2.1.2+cu118" +set "PIN_NUMPY=numpy==1.26.4" +set "PIN_NERFSTUDIO=nerfstudio==1.0.3" +set "PIN_TYRO=tyro==0.8.12" + +set "PIN_PYCOLMAP_RMBRUALLA=git+https://github.com/rmbrualla/pycolmap.git" +set "PIN_TCNN_GIT=git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch" + +set "PIN_VISER=viser==0.1.26" +set "PIN_NERFACC=nerfacc==0.5.2" +set "PIN_GSPLAT=gsplat==1.5.3" +set "PIN_HF_HUB=huggingface-hub==1.9.0" +set "PIN_BITSANDBYTES=bitsandbytes==0.49.2" + +if not exist "%LOCK_DIR%" mkdir "%LOCK_DIR%" 2>nul + +call :clear_rocm_env +if errorlevel 1 exit /b %errorlevel% + +echo. +echo ====================================================== +echo Extras target env: %TARGET_ENV% +echo Conda exe: %CONDA_EXE% +echo Python script: %PY_SCRIPT% +echo ====================================================== +echo. +echo Available extras: +echo 1. Install / repair pinned Nerfstudio core packages +echo 2. Install Zip-NeRF ^(Windows-patched^) +echo 3. Install rmbrualla pycolmap only +echo 4. Install torch-scatter only +echo 5. Run ns-install-cli only +echo 6. Re-pin current target env only +echo 7. Install support packages ^(nerfacc, gsplat, viser, hf-hub, bitsandbytes, tyro^) +echo 8. Full recommended extras bootstrap ^(core + support + Zip-NeRF^) +echo 9. Install Tetra-NeRF (Windows-patched) +echo. +set /p "CHOICE=Enter choice [1-9]: " + +if "%CHOICE%"=="1" goto :do_core +if "%CHOICE%"=="2" goto :do_zipnerf +if "%CHOICE%"=="3" goto :do_pycolmap +if "%CHOICE%"=="4" goto :do_torchscatter +if "%CHOICE%"=="5" goto :do_ns_cli +if "%CHOICE%"=="6" goto :do_repin +if "%CHOICE%"=="7" goto :do_support +if "%CHOICE%"=="8" goto :full_bootstrap +if "%CHOICE%"=="9" goto :do_tetra_nerf +echo [ERROR] Invalid choice. +exit /b 1 + +:full_bootstrap +echo. +echo [STEP] Ensuring support packages used by extra methods... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps %PIN_NERFACC% %PIN_GSPLAT% %PIN_VISER% %PIN_HF_HUB% %PIN_BITSANDBYTES% %PIN_TYRO% +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Ensuring pinned Nerfstudio core packages... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps %PIN_NERFSTUDIO% +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Installing rmbrualla pycolmap... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps --no-build-isolation git+https://github.com/rmbrualla/pycolmap.git +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Installing torch-scatter... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps torch-scatter==2.1.2+pt21cu118 -f https://data.pyg.org/whl/torch-2.1.0+cu118.html +if errorlevel 1 exit /b %errorlevel% + +echo. +echo [STEP] Installing Zip-NeRF... +call :install_zipnerf +if errorlevel 1 exit /b %errorlevel% + +call :run_ns_install_cli +if errorlevel 1 exit /b %errorlevel% + +call :repin_target_env +exit /b %errorlevel% + +:do_full +call :ensure_support_packages +if errorlevel 1 exit /b %errorlevel% +call :install_zipnerf +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_core +call :ensure_core_stack +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_support +call :ensure_support_packages +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_zipnerf +call :install_zipnerf +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_pycolmap +call :install_rmbrualla_pycolmap +if errorlevel 1 exit /b %errorlevel% +call :ns_register_and_repin +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_torchscatter +call :install_torch_scatter +if errorlevel 1 exit /b %errorlevel% +call :ns_register_and_repin +if errorlevel 1 exit /b %errorlevel% +goto :success + +:do_ns_cli +call :run_in_env python -m ns_install_cli +if errorlevel 1 ( + call :run_in_env ns-install-cli + if errorlevel 1 exit /b %errorlevel% +) +goto :success + +:do_repin +call :repin_target +if errorlevel 1 exit /b %errorlevel% +goto :success + +:success +echo. +echo [OK] Extras flow completed successfully. +exit /b 0 + +:ensure_core_stack +echo. +echo [STEP] Ensuring pinned Nerfstudio core stack... +call :clear_rocm_env +call :run_in_env python -m pip install --upgrade pip setuptools^<81 wheel +if errorlevel 1 exit /b %errorlevel% +call :run_in_env python -m pip install --upgrade --force-reinstall %PIN_NUMPY% +if errorlevel 1 exit /b %errorlevel% +call :run_in_env python -m pip install --upgrade --force-reinstall %PIN_TORCH% %PIN_TORCHVISION% %PIN_TORCHAUDIO% --index-url https://download.pytorch.org/whl/cu118 +if errorlevel 1 exit /b %errorlevel% +call :run_in_env python -m pip install --upgrade --force-reinstall %PIN_NUMPY% +if errorlevel 1 exit /b %errorlevel% +call :run_in_env python -m pip install --upgrade --force-reinstall %PIN_NERFSTUDIO% %PIN_TYRO% +if errorlevel 1 exit /b %errorlevel% +call :set_cuda_arch_env +call :run_in_env python -m pip install -v --upgrade --force-reinstall --no-build-isolation --no-cache-dir %PIN_TCNN_GIT% +if errorlevel 1 exit /b %errorlevel% +call :ns_register_and_repin +exit /b %errorlevel% + +:set_cuda_env +if not defined CUDA_HOME if exist "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8" set "CUDA_HOME=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8" +if not defined CUDA_PATH if defined CUDA_HOME set "CUDA_PATH=%CUDA_HOME%" +if defined CUDA_HOME set "PATH=%CUDA_HOME%\bin;%CUDA_HOME%\libnvvp;%PATH%" +if not defined TCNN_CUDA_ARCHITECTURES set "TCNN_CUDA_ARCHITECTURES=86" +if not defined TORCH_CUDA_ARCH_LIST set "TORCH_CUDA_ARCH_LIST=8.6" +if not defined MAX_JOBS set "MAX_JOBS=1" +exit /b 0 + +:do_tetra_nerf +call :install_tetra_nerf +if errorlevel 1 exit /b %errorlevel% +goto :success + +:install_tetra_nerf +echo. +echo [STEP] Installing Tetra-NeRF with Windows-safe patches... +call :clear_rocm_env +if errorlevel 1 exit /b %errorlevel% + +if not exist "%ROOT_DIR%\tetra-nerf" ( + echo [INFO] Cloning tetra-nerf... + call :run_in_env git clone https://github.com/jkulhanek/tetra-nerf.git + if errorlevel 1 exit /b %errorlevel% +) + +call :apply_patch_file "%ROOT_DIR%\Extra-Methods-Patches\tetra-nerf\CMakeLists.txt" "%ROOT_DIR%\tetra-nerf\CMakeLists.txt" +if errorlevel 1 exit /b %errorlevel% + +call :apply_patch_file "%ROOT_DIR%\Extra-Methods-Patches\tetra-nerf\cmake\FindTorch.cmake" "%ROOT_DIR%\tetra-nerf\cmake\FindTorch.cmake" +if errorlevel 1 exit /b %errorlevel% + +call :apply_patch_file "%ROOT_DIR%\Extra-Methods-Patches\tetra-nerf\cmake\FindCUDA.cmake" "%ROOT_DIR%\tetra-nerf\cmake\FindCUDA.cmake" +if errorlevel 1 exit /b %errorlevel% + +call :apply_patch_file "%ROOT_DIR%\Extra-Methods-Patches\tetra-nerf\src\tetrahedra_tracer.h" "%ROOT_DIR%\tetra-nerf\src\tetrahedra_tracer.h" +if errorlevel 1 exit /b %errorlevel% + +call :apply_patch_file "%ROOT_DIR%\Extra-Methods-Patches\tetra-nerf\src\utils\vec_math.h" "%ROOT_DIR%\tetra-nerf\src\utils\vec_math.h" +if errorlevel 1 exit /b %errorlevel% + +for %%I in ("C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8") do set "CUDA118_SHORT=%%~sI" +for %%I in ("C:\Program Files\NVIDIA Corporation\OptiX SDK 9.1.0") do set "OPTIX_SHORT=%%~sI" + +set "CUDA118_CMAKE=%CUDA118_SHORT:\=/%" +set "OPTIX_CMAKE=%OPTIX_SHORT:\=/%" +set "TETRA_SCRIPT=%TEMP%\tetra_build_%RANDOM%.cmd" + +> "%TETRA_SCRIPT%" echo @echo off +>> "%TETRA_SCRIPT%" echo setlocal +>> "%TETRA_SCRIPT%" echo cd /d "%ROOT_DIR%\tetra-nerf" +>> "%TETRA_SCRIPT%" echo if exist build-cu118 rmdir /S /Q build-cu118 +>> "%TETRA_SCRIPT%" echo set "PATH=%CUDA118_SHORT%\bin;%%PATH%%" +>> "%TETRA_SCRIPT%" echo cmake -S . -B build-cu118 -T cuda="%CUDA118_CMAKE%" -DCUDA_TOOLKIT_ROOT_DIR="%CUDA118_CMAKE%" -DOptiX_INSTALL_DIR="%OPTIX_CMAKE%" +>> "%TETRA_SCRIPT%" echo if errorlevel 1 exit /b 1 +>> "%TETRA_SCRIPT%" echo cmake --build build-cu118 --config Release +>> "%TETRA_SCRIPT%" echo if errorlevel 1 exit /b 1 +>> "%TETRA_SCRIPT%" echo python -m pip install -e . --no-deps + +call :run_in_env cmd /d /s /c ""%TETRA_SCRIPT%"" +set "TETRA_RC=%errorlevel%" +del /Q "%TETRA_SCRIPT%" >nul 2>nul + +if not "%TETRA_RC%"=="0" exit /b %TETRA_RC% + +call :ns_register_and_repin +exit /b %errorlevel% + +:install_zipnerf +echo. +echo [STEP] Installing Zip-NeRF with Windows-safe patches... +call :clear_rocm_env +if errorlevel 1 exit /b %errorlevel% + +if not exist "%ROOT_DIR%\zipnerf-pytorch" ( + echo [INFO] Cloning zipnerf-pytorch... + call :run_in_env git clone https://github.com/SuLvXiangXin/zipnerf-pytorch.git + if errorlevel 1 exit /b %errorlevel% +) + +set "ZIP_PATCH_SRC=%ROOT_DIR%\Extra-Methods-Patches\zipnerf-pytorch\extensions\cuda\setup.py" +set "ZIP_PATCH_DST=%ROOT_DIR%\zipnerf-pytorch\extensions\cuda\setup.py" + +call :apply_patch_file "%ZIP_PATCH_SRC%" "%ZIP_PATCH_DST%" +if errorlevel 1 exit /b %errorlevel% +call :set_cuda_arch_env +call :set_cuda_env + +echo [INFO] Installing Zip-NeRF CUDA extension... +call :run_in_env cmd /d /s /c "cd /d ""%ROOT_DIR%\zipnerf-pytorch\extensions\cuda"" && python -m pip install --no-build-isolation ." +if errorlevel 1 ( + echo [WARN] pip install . failed, trying setup.py install fallback... + call :set_cuda_env + call :run_in_env cmd /d /s /c "cd /d ""%ROOT_DIR%\zipnerf-pytorch\extensions\cuda"" && python setup.py install" + if errorlevel 1 exit /b %errorlevel% +) + +echo [INFO] Installing Zip-NeRF editable package... +call :run_in_env cmd /d /s /c "cd /d ""%ROOT_DIR%\zipnerf-pytorch"" && python -m pip install -e . --no-deps" +if errorlevel 1 exit /b %errorlevel% + +call :run_in_env python -m pip install --upgrade tyro==0.8.12 +if errorlevel 1 exit /b %errorlevel% + +call :copy_zipnerf_configs +if errorlevel 1 exit /b %errorlevel% + +call :ns_register_and_repin +exit /b %errorlevel% + +:install_rmbrualla_pycolmap +echo [INFO] Installing rmbrualla pycolmap for Zip-NeRF compatibility... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps --no-build-isolation git+https://github.com/rmbrualla/pycolmap.git +exit /b %errorlevel% + +:install_torch_scatter +echo [INFO] Installing torch-scatter compatible with torch 2.1/cu118... +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps torch-scatter==2.1.2+pt21cu118 -f https://data.pyg.org/whl/torch-2.1.0+cu118.html +exit /b %errorlevel% + +:copy_zipnerf_configs +set "ZIP_CFG_SRC=%ROOT_DIR%\zipnerf-pytorch\zipnerf_ns\config" +set "ZIP_CFG_DST=" +for /f "usebackq delims=" %%I in (`call "%CONDA_EXE%" run -n "%TARGET_ENV%" python -c "import pathlib, nerfstudio; print(pathlib.Path(nerfstudio.__file__).resolve().parent / 'configs')"` ) do set "ZIP_CFG_DST=%%I" +if not defined ZIP_CFG_DST ( + echo [WARN] Could not resolve nerfstudio config path automatically. Skipping config copy. + exit /b 0 +) +if exist "%ZIP_CFG_SRC%" ( + echo [INFO] Copying Zip-NeRF config files into nerfstudio config dir... + if not exist "%ZIP_CFG_DST%" mkdir "%ZIP_CFG_DST%" 2>nul + xcopy /E /Y /I "%ZIP_CFG_SRC%\*" "%ZIP_CFG_DST%\" >nul + exit /b 0 +) +echo [WARN] Zip-NeRF config source not found, skipping copy: %ZIP_CFG_SRC% +exit /b 0 + +:ns_register_and_repin +echo [INFO] Running ns-install-cli to register plugins... +call :run_in_env ns-install-cli +if errorlevel 1 ( + call :run_in_env python -m nerfstudio.scripts.completions.install + if errorlevel 1 exit /b %errorlevel% +) +call :repin_target +exit /b %errorlevel% + +:repin_target +echo [INFO] Re-applying protected pinned stack after extra installation... +call :clear_rocm_env +call :run_in_env python "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" repin --skip-conda +exit /b %errorlevel% + +:set_cuda_arch_env +if not defined TCNN_CUDA_ARCHITECTURES set "TCNN_CUDA_ARCHITECTURES=86" +if not defined TORCH_CUDA_ARCH_LIST set "TORCH_CUDA_ARCH_LIST=8.6" +if not defined MAX_JOBS set "MAX_JOBS=1" +exit /b 0 + +:ensure_support_packages +echo. +echo [STEP] Ensuring support packages used by extra methods... +call :clear_rocm_env + +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps %PIN_TYRO% %PIN_NERFACC% %PIN_VISER% %PIN_HF_HUB% %PIN_BITSANDBYTES% +if errorlevel 1 exit /b %errorlevel% + +call :run_in_env python -m pip install --upgrade --force-reinstall --no-deps %PIN_GSPLAT% +if errorlevel 1 exit /b %errorlevel% + +call :run_in_env python -c "import torch; print(torch.__version__); import gsplat; from gsplat._torch_impl import quat_to_rotmat; print('gsplat OK')" +if errorlevel 1 exit /b %errorlevel% + +call :ns_register_and_repin +exit /b %errorlevel% + +:run_in_env +call :clear_rocm_env +echo [RUN] %* +call "%CONDA_EXE%" run -n "%TARGET_ENV%" --no-capture-output %* +exit /b %errorlevel% + +:repin_target_env +echo. +echo [STEP] Re-pinning target env after extras... +call "%CONDA_BAT%" activate "%TARGET_ENV%" +if errorlevel 1 exit /b %errorlevel% +python "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" repin --skip-conda +set "_REP_RC=%errorlevel%" +call conda deactivate >nul 2>nul +exit /b %_REP_RC% + +:run_ns_install_cli +echo. +echo [STEP] Running ns-install-cli... +call "%CONDA_BAT%" activate "%TARGET_ENV%" +if errorlevel 1 exit /b %errorlevel% +where ns-install-cli >nul 2>nul +if errorlevel 1 ( + python -m ns.install_cli +) else ( + ns-install-cli +) +set "_NSCLI_RC=%errorlevel%" +call conda deactivate >nul 2>nul +exit /b %_NSCLI_RC% + +:apply_patch_file +set "PATCH_SRC=%~1" +set "PATCH_DST=%~2" + +if not defined PATCH_SRC ( + echo [ERROR] Missing patch source path. + exit /b 1 +) +if not defined PATCH_DST ( + echo [ERROR] Missing patch destination path. + exit /b 1 +) + +if not exist "%PATCH_SRC%" ( + echo [ERROR] Patch source not found: %PATCH_SRC% + exit /b 1 +) + +if not exist "%PATCH_DST%" ( + echo [ERROR] Patch target not found: %PATCH_DST% + exit /b 1 +) + +if not exist "%PATCH_DST%.orig" ( + copy /Y "%PATCH_DST%" "%PATCH_DST%.orig" >nul + if errorlevel 1 ( + echo [ERROR] Failed creating backup: %PATCH_DST%.orig + exit /b 1 + ) +) + +copy /Y "%PATCH_SRC%" "%PATCH_DST%" >nul +if errorlevel 1 ( + echo [ERROR] Failed applying patch file. + exit /b 1 +) + +echo [OK] Applied patch: +echo SRC: %PATCH_SRC% +echo DST: %PATCH_DST% +exit /b 0 + +:clear_rocm_env +set "ROCM_HOME=" +set "ROCM_PATH=" +set "HIP_HOME=" +set "HIP_PATH=" +set "HCC_HOME=" +set "HIP_PATH_57=" +set "HIP_DEVICE_LIB_PATH=" +set "PYTORCH_ROCM_ARCH=" +exit /b 0 + + diff --git a/find_colmap_defaults.py b/find_colmap_defaults.py new file mode 100644 index 0000000000..b12890233a --- /dev/null +++ b/find_colmap_defaults.py @@ -0,0 +1,13 @@ +from pathlib import Path + +roots = ["splatfacto-w", "NeRFtoGSandBack", "opennerf", "relationfield", "lerf", "pynerf"] + +for root in roots: + rp = Path(root) + if not rp.exists(): + continue + for p in rp.rglob("*.py"): + s = p.read_text(encoding="utf-8", errors="ignore") + for i, line in enumerate(s.splitlines(), start=1): + if "ColmapDataParserConfig(" in line: + print(f"{p}:{i}: {line.strip()}") \ No newline at end of file diff --git a/find_dataparser_union_defaults.py b/find_dataparser_union_defaults.py new file mode 100644 index 0000000000..081bc1640b --- /dev/null +++ b/find_dataparser_union_defaults.py @@ -0,0 +1,27 @@ +from pathlib import Path + +roots = [ + Path("opennerf"), + Path("NeRFtoGSandBack"), + Path("relationfield"), + Path("livescene"), + Path("pynerf"), + Path("splatfacto-w"), + Path("lerf"), +] + +needles = [ + "dataparser: AnnotatedDataParserUnion = ", + "dataparser: AnnotatedDataParserUnion=", +] + +for root in roots: + if not root.exists(): + continue + for p in root.rglob("*.py"): + s = p.read_text(encoding="utf-8", errors="ignore") + if any(n in s for n in needles): + print(f"\n== {p} ==") + for line in s.splitlines(): + if "dataparser:" in line and "AnnotatedDataParserUnion" in line: + print(line) \ No newline at end of file diff --git a/find_patch_field.py b/find_patch_field.py new file mode 100644 index 0000000000..6145b6a568 --- /dev/null +++ b/find_patch_field.py @@ -0,0 +1,12 @@ +from pathlib import Path + +for p in Path(".").rglob("*.py"): + try: + s = p.read_text(encoding="utf-8", errors="ignore") + except Exception: + continue + if "patch_tile_size_range" in s or "(0.05, 0.5)" in s: + print(f"\n== {p} ==") + for line in s.splitlines(): + if "patch_tile_size_range" in line or "(0.05, 0.5)" in line: + print(line) \ No newline at end of file diff --git a/find_tyro_tuple_issue.py b/find_tyro_tuple_issue.py new file mode 100644 index 0000000000..82892bf0f0 --- /dev/null +++ b/find_tyro_tuple_issue.py @@ -0,0 +1,27 @@ +from pathlib import Path + +roots = [ + Path("opennerf"), + Path("NeRFtoGSandBack"), + Path("relationfield"), + Path("lerf"), +] + +for root in roots: + if not root.exists(): + continue + for p in root.rglob("*.py"): + s = p.read_text(encoding="utf-8", errors="ignore") + hit = False + lines = [] + for line in s.splitlines(): + if "hashgrid_layers" in line or "negatives" in line: + lines.append(line) + hit = True + elif "Tuple[int]" in line or "Tuple[str]" in line: + lines.append(line) + hit = True + if hit: + print(f"\n== {p} ==") + for line in lines: + print(line) \ No newline at end of file diff --git a/freeze_current_env_to_lock.bat b/freeze_current_env_to_lock.bat new file mode 100644 index 0000000000..d27d5192f7 --- /dev/null +++ b/freeze_current_env_to_lock.bat @@ -0,0 +1,445 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion +cd /d "%~dp0" + +set "ROOT_DIR=%CD%" +set "LOCK_DIR=%ROOT_DIR%\deps-lock" +set "PY_SCRIPT=%ROOT_DIR%\deps_lock.py" +set "PORTABLE_ENV_BAT=%ROOT_DIR%\portable_env.bat" +set "INSTALLER_SELECTION_JSON=%LOCK_DIR%\installer-selection.json" +set "MSVC_TOOLSET_LIST_FILE=%LOCK_DIR%\msvc-toolsets.txt" +set "MSVC_SELECTED_LOG=%LOCK_DIR%\msvc-selected.txt" + +if not exist "%LOCK_DIR%" mkdir "%LOCK_DIR%" 2>nul +if not exist "%PY_SCRIPT%" ( + echo [ERROR] Missing "%PY_SCRIPT%" + exit /b 1 +) + +call :select_conda_backend +if errorlevel 1 exit /b %errorlevel% + +call :activate_target_env "%~1" +if errorlevel 1 exit /b %errorlevel% + +call :select_gpu_arch +if errorlevel 1 exit /b %errorlevel% + +call :select_msvc_toolset +if errorlevel 1 exit /b %errorlevel% + +call :write_installer_selection_json +if errorlevel 1 exit /b %errorlevel% + +echo. +echo ============================================ +echo Freeze current env to deps-lock +echo ============================================ +echo ROOT_DIR = %ROOT_DIR% +echo LOCK_DIR = %LOCK_DIR% +echo PY_SCRIPT = %PY_SCRIPT% +echo CONDA_MODE = %CONDA_MODE% +echo CONDA_ROOT = %SELECTED_CONDA_ROOT% +echo CONDA_DEFAULT_ENV = %CONDA_DEFAULT_ENV% +echo CONDA_PREFIX = %CONDA_PREFIX% +echo GPU_NAME = %GPU_NAME% +echo CUDA_ARCH = %CUDA_ARCH% +echo TCNN_CUDA_ARCHITECTURES = %TCNN_CUDA_ARCHITECTURES% +echo Preferred MSVC mode = %PREFERRED_MSVC% +echo Available toolsets log = %MSVC_TOOLSET_LIST_FILE% +echo Bootstrap result log = %MSVC_SELECTED_LOG% +echo ============================================ + +"%PYTHON_EXE%" "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" export +if errorlevel 1 exit /b %errorlevel% + +echo. +set "MISSING=0" +for %%F in ( + "%LOCK_DIR%\pip-freeze-all.txt" + "%LOCK_DIR%\pip-freeze-replay.txt" + "%LOCK_DIR%\build-plan.json" + "%LOCK_DIR%\lock-meta.json" + "%LOCK_DIR%\numpy-compat-audit.txt" + "%LOCK_DIR%\msvc-toolsets.txt" + "%LOCK_DIR%\msvc-selected.txt" +) do ( + if exist %%~F ( + echo [OK] Exists: %%~F + ) else ( + echo [ERROR] Missing expected file: %%~F + set "MISSING=1" + ) +) + +set "FOUND_CONDA_LOCK=0" +for %%F in ("%LOCK_DIR%\conda-explicit-*.txt") do ( + if exist "%%~F" ( + echo [OK] Exists: %%~F + set "FOUND_CONDA_LOCK=1" + ) +) + +if "%MISSING%"=="1" exit /b 1 + +echo. +echo [DONE] Freeze completed. +exit /b 0 + + +:activate_target_env +set "TARGET_ENV=%~1" + +if defined TARGET_ENV ( + echo [INFO] Activating target env: %TARGET_ENV% + call "%CONDA_BAT%" activate "%TARGET_ENV%" + exit /b %errorlevel% +) + +if defined CONDA_PREFIX ( + echo [INFO] Current active env detected: + echo %CONDA_PREFIX% + set "USE_CURRENT=" + set /p "USE_CURRENT=Export CURRENT active env? [Y/n]: " + if /I "!USE_CURRENT!"=="N" ( + set "TARGET_ENV=" + set /p "TARGET_ENV=Enter conda env name to activate before export: " + if defined TARGET_ENV ( + call "%CONDA_BAT%" activate "%TARGET_ENV%" + exit /b %errorlevel% + ) + ) else ( + exit /b 0 + ) +) + +exit /b 0 + + +:select_conda_backend +echo. +echo Freeze source conda backend: +echo 1. portable ^(project-local .conda^) +echo 2. system ^(existing Anaconda/Miniconda on this PC^) +echo 3. current ^(derive from active shell / PATH^) + +set "CONDA_MODE_CHOICE=" +set /p "CONDA_MODE_CHOICE=Choose source backend [1-3, default 1]: " +if not defined CONDA_MODE_CHOICE set "CONDA_MODE_CHOICE=1" + +if "%CONDA_MODE_CHOICE%"=="1" call :resolve_named_conda_backend portable +if "%CONDA_MODE_CHOICE%"=="2" call :resolve_named_conda_backend system +if "%CONDA_MODE_CHOICE%"=="3" call :resolve_named_conda_backend current +if errorlevel 1 exit /b %errorlevel% + +if not defined RESOLVED_CONDA_MODE ( + echo [ERROR] Invalid conda backend choice. + exit /b 1 +) + +set "CONDA_MODE=%RESOLVED_CONDA_MODE%" +set "SELECTED_CONDA_ROOT=%RESOLVED_CONDA_ROOT%" +set "CONDA_EXE=%RESOLVED_CONDA_EXE%" +set "CONDA_BAT=%RESOLVED_CONDA_BAT%" +set "PYTHON_EXE=%RESOLVED_PYTHON_EXE%" +exit /b 0 + + +:resolve_named_conda_backend +set "REQ_MODE=%~1" +set "RESOLVED_CONDA_MODE=" +set "RESOLVED_CONDA_ROOT=" +set "RESOLVED_CONDA_EXE=" +set "RESOLVED_CONDA_BAT=" +set "RESOLVED_PYTHON_EXE=" + +if /I "%REQ_MODE%"=="portable" goto :resolve_portable +if /I "%REQ_MODE%"=="system" goto :resolve_system +if /I "%REQ_MODE%"=="current" goto :resolve_current + +echo [ERROR] Unknown conda backend: %REQ_MODE% +exit /b 1 + + +:resolve_portable +if not exist "%PORTABLE_ENV_BAT%" ( + echo [ERROR] Missing portable helper: %PORTABLE_ENV_BAT% + exit /b 1 +) + +call "%PORTABLE_ENV_BAT%" +if errorlevel 1 exit /b %errorlevel% + +if not defined PORTABLE_CONDA_ROOT if exist "%ROOT_DIR%\.conda\Scripts\conda.exe" set "PORTABLE_CONDA_ROOT=%ROOT_DIR%\.conda" +if not defined PORTABLE_CONDA_ROOT ( + echo [ERROR] PORTABLE_CONDA_ROOT not exported by portable_env.bat + exit /b 1 +) + +set "RESOLVED_CONDA_MODE=portable" +set "RESOLVED_CONDA_ROOT=%PORTABLE_CONDA_ROOT%" +set "RESOLVED_CONDA_EXE=%PORTABLE_CONDA_ROOT%\Scripts\conda.exe" +set "RESOLVED_CONDA_BAT=%PORTABLE_CONDA_ROOT%\condabin\conda.bat" +set "RESOLVED_PYTHON_EXE=%PORTABLE_CONDA_ROOT%\python.exe" +goto :validate_resolved_conda + + +:resolve_system +call :detect_system_conda_root +if errorlevel 1 exit /b %errorlevel% + +set "RESOLVED_CONDA_MODE=system" +set "RESOLVED_CONDA_ROOT=%SYSTEM_CONDA_ROOT%" +set "RESOLVED_CONDA_EXE=%SYSTEM_CONDA_ROOT%\Scripts\conda.exe" +set "RESOLVED_CONDA_BAT=%SYSTEM_CONDA_ROOT%\condabin\conda.bat" +set "RESOLVED_PYTHON_EXE=%SYSTEM_CONDA_ROOT%\python.exe" +goto :validate_resolved_conda + + +:resolve_current +if defined CONDA_EXE ( + for %%I in ("%CONDA_EXE%") do set "CUR_SCRIPTS_DIR=%%~dpI" + for %%I in ("!CUR_SCRIPTS_DIR!..") do set "CUR_CONDA_ROOT=%%~fI" +) + +if not defined CUR_CONDA_ROOT for /f "delims=" %%I in ('where conda.exe 2^>nul') do if not defined CUR_CONDA_ROOT ( + for %%J in ("%%I") do set "CUR_SCRIPTS_DIR=%%~dpJ" + for %%J in ("!CUR_SCRIPTS_DIR!..") do set "CUR_CONDA_ROOT=%%~fJ" +) + +if not defined CUR_CONDA_ROOT ( + echo [ERROR] Could not derive current conda root from active shell / PATH. + exit /b 1 +) + +set "RESOLVED_CONDA_MODE=current" +set "RESOLVED_CONDA_ROOT=%CUR_CONDA_ROOT%" +set "RESOLVED_CONDA_EXE=%CUR_CONDA_ROOT%\Scripts\conda.exe" +set "RESOLVED_CONDA_BAT=%CUR_CONDA_ROOT%\condabin\conda.bat" +set "RESOLVED_PYTHON_EXE=%CUR_CONDA_ROOT%\python.exe" +goto :validate_resolved_conda + + +:validate_resolved_conda +if not exist "%RESOLVED_CONDA_EXE%" ( + echo [ERROR] Conda executable not found: %RESOLVED_CONDA_EXE% + exit /b 1 +) +if not exist "%RESOLVED_PYTHON_EXE%" ( + echo [ERROR] Python executable not found: %RESOLVED_PYTHON_EXE% + exit /b 1 +) +exit /b 0 + + +:detect_system_conda_root +set "SYSTEM_CONDA_ROOT=" + +if defined CONDA_EXE ( + echo %CONDA_EXE% | find /I "%ROOT_DIR%\.conda" >nul + if errorlevel 1 ( + for %%I in ("%CONDA_EXE%") do set "_sys_scripts=%%~dpI" + for %%I in ("!_sys_scripts!..") do set "SYSTEM_CONDA_ROOT=%%~fI" + ) +) + +if not defined SYSTEM_CONDA_ROOT for /f "delims=" %%I in ('where conda.exe 2^>nul') do ( + echo %%I | find /I "%ROOT_DIR%\.conda" >nul + if errorlevel 1 if not defined SYSTEM_CONDA_ROOT ( + for %%J in ("%%I") do set "_sys_scripts=%%~dpJ" + for %%J in ("!_sys_scripts!..") do set "SYSTEM_CONDA_ROOT=%%~fJ" + ) +) + +if not defined SYSTEM_CONDA_ROOT if exist "%UserProfile%\miniconda3\Scripts\conda.exe" set "SYSTEM_CONDA_ROOT=%UserProfile%\miniconda3" +if not defined SYSTEM_CONDA_ROOT if exist "%UserProfile%\anaconda3\Scripts\conda.exe" set "SYSTEM_CONDA_ROOT=%UserProfile%\anaconda3" +if not defined SYSTEM_CONDA_ROOT if exist "%ProgramData%\Miniconda3\Scripts\conda.exe" set "SYSTEM_CONDA_ROOT=%ProgramData%\Miniconda3" +if not defined SYSTEM_CONDA_ROOT if exist "%ProgramData%\Anaconda3\Scripts\conda.exe" set "SYSTEM_CONDA_ROOT=%ProgramData%\Anaconda3" + +if not defined SYSTEM_CONDA_ROOT ( + echo [ERROR] Could not find a system conda installation. + exit /b 1 +) +exit /b 0 + + +:select_gpu_arch +set "GPU_NAME=unknown" +set "CUDA_ARCH=" +set "TCNN_CUDA_ARCHITECTURES=" + +echo. +echo GPU arch mode: +echo 1. Auto-detect from nvidia-smi +echo 2. Manual entry +echo 3. Leave blank / skip + +set "GPU_MODE=" +set /p "GPU_MODE=Choose GPU arch mode [1-3, default 1]: " +if not defined GPU_MODE set "GPU_MODE=1" + +if "%GPU_MODE%"=="1" goto :gpu_auto +if "%GPU_MODE%"=="2" goto :gpu_manual +if "%GPU_MODE%"=="3" goto :gpu_skip + +echo [ERROR] Invalid GPU mode. +exit /b 1 + +:gpu_skip +exit /b 0 + +:gpu_auto +for /f "usebackq delims=" %%G in (`nvidia-smi --query-gpu=name --format=csv,noheader 2^>nul`) do if /I "!GPU_NAME!"=="unknown" set "GPU_NAME=%%G" +call :map_gpu_to_arch "%GPU_NAME%" +if not defined CUDA_ARCH goto :gpu_manual_default +set "TCNN_CUDA_ARCHITECTURES=%CUDA_ARCH%" +exit /b 0 + +:gpu_manual_default +set "GPU_NAME=manual" +set /p "CUDA_ARCH=Enter CUDA arch [default 86 for RTX 3090]: " +if not defined CUDA_ARCH set "CUDA_ARCH=86" +set "TCNN_CUDA_ARCHITECTURES=%CUDA_ARCH%" +exit /b 0 + +:gpu_manual +set "GPU_NAME=manual" +set /p "CUDA_ARCH=Enter CUDA arch (75, 80, 86, 89, 90, 120 ...): " +if not defined CUDA_ARCH exit /b 1 +set "TCNN_CUDA_ARCHITECTURES=%CUDA_ARCH%" +exit /b 0 + +:map_gpu_to_arch +set "GPU_LABEL=%~1" +set "CUDA_ARCH=" +echo %GPU_LABEL% | find /I "3090" >nul && set "CUDA_ARCH=86" +echo %GPU_LABEL% | find /I "4090" >nul && set "CUDA_ARCH=89" +echo %GPU_LABEL% | find /I "H100" >nul && set "CUDA_ARCH=90" +exit /b 0 + + +:select_msvc_toolset +set "PREFERRED_MSVC=" +echo. +echo Preferred MSVC toolset: +echo 1. auto ^(prefer 14.38 if found, else best compatible^) +echo 2. 14.38 ^(force VS2022 v143 14.38 toolset if installed^) +echo 3. 14 ^(any 14.x compatible MSVC^) +echo 4. system ^(do not force; use current/default MSVC on PATH^) +set /p "MSVC_CHOICE=Choose preferred MSVC toolset [1-4, default 1]: " +if not defined MSVC_CHOICE set "MSVC_CHOICE=1" + +if "%MSVC_CHOICE%"=="1" set "PREFERRED_MSVC=auto" +if "%MSVC_CHOICE%"=="2" set "PREFERRED_MSVC=14.38" +if "%MSVC_CHOICE%"=="3" set "PREFERRED_MSVC=14" +if "%MSVC_CHOICE%"=="4" set "PREFERRED_MSVC=system" + +if not defined PREFERRED_MSVC ( + echo [ERROR] Invalid MSVC choice. + exit /b 1 +) + +if not exist "%LOCK_DIR%" mkdir "%LOCK_DIR%" 2>nul + +> "%MSVC_TOOLSET_LIST_FILE%" echo Detected MSVC toolsets: +for %%R in ( + "%ProgramFiles%\Microsoft Visual Studio\2022\BuildTools" + "%ProgramFiles%\Microsoft Visual Studio\2022\Community" + "%ProgramFiles%\Microsoft Visual Studio\2022\Professional" + "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\Community" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\Professional" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\Enterprise" +) do ( + if exist "%%~R\VC\Tools\MSVC" ( + for /d %%T in ("%%~R\VC\Tools\MSVC\*") do ( + >> "%MSVC_TOOLSET_LIST_FILE%" echo %%~nxT ^| %%~R + ) + ) +) + +if exist "%MSVC_TOOLSET_LIST_FILE%" type "%MSVC_TOOLSET_LIST_FILE%" +exit /b 0 + + +:write_installer_selection_json +if not exist "%LOCK_DIR%" mkdir "%LOCK_DIR%" 2>nul +if not exist "%LOCK_DIR%" ( + echo [ERROR] Unable to create lock directory: %LOCK_DIR% + exit /b 1 +) + +set "MSVC_HINT=" +set "MSVC_INSTALL_HINT=" +set "MSVC_INSTALL_HINT_SHORT=" + +if exist "%MSVC_TOOLSET_LIST_FILE%" ( + for /f "usebackq tokens=1,* delims=|" %%A in ("%MSVC_TOOLSET_LIST_FILE%") do ( + set "MSVC_VER=%%~A" + set "MSVC_LOC=%%~B" + call :trim_var MSVC_VER + call :trim_var MSVC_LOC + + if defined MSVC_VER ( + echo !MSVC_VER! | findstr /R "^[0-9][0-9]*\.[0-9][0-9]*" >nul + if not errorlevel 1 ( + if /I "%PREFERRED_MSVC%"=="auto" ( + if not defined MSVC_HINT if /I "!MSVC_VER:~0,5!"=="14.38" ( + set "MSVC_HINT=!MSVC_VER!" + set "MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + ) else if /I "%PREFERRED_MSVC%"=="14.38" ( + if not defined MSVC_HINT if /I "!MSVC_VER:~0,5!"=="14.38" ( + set "MSVC_HINT=!MSVC_VER!" + set "MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + ) else if /I "%PREFERRED_MSVC%"=="14" ( + if not defined MSVC_HINT if /I "!MSVC_VER:~0,3!"=="14." ( + set "MSVC_HINT=!MSVC_VER!" + set "MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + ) + ) + ) + ) +) + +if not defined MSVC_HINT set "MSVC_HINT=%PREFERRED_MSVC%" +if defined MSVC_INSTALL_HINT call :to_short_path "%MSVC_INSTALL_HINT%" MSVC_INSTALL_HINT_SHORT +if not defined MSVC_INSTALL_HINT_SHORT set "MSVC_INSTALL_HINT_SHORT=%MSVC_INSTALL_HINT%" + +"%PYTHON_EXE%" -c "import json, pathlib; from datetime import datetime, timezone; p=pathlib.Path(r'%INSTALLER_SELECTION_JSON%'); p.parent.mkdir(parents=True, exist_ok=True); data={'cuda_arch': r'%CUDA_ARCH%','tcnn_cuda_architectures': r'%TCNN_CUDA_ARCHITECTURES%','gpu_name': r'%GPU_NAME%','preferred_msvc': r'%PREFERRED_MSVC%','preferred_msvc_mode': r'%PREFERRED_MSVC%','selected_msvc_toolset_hint': r'%MSVC_HINT%','selected_msvc_installation_hint': r'%MSVC_INSTALL_HINT_SHORT%','conda_mode': r'%CONDA_MODE%','conda_root': r'%SELECTED_CONDA_ROOT%','written_utc': datetime.now(timezone.utc).isoformat()}; p.write_text(json.dumps(data, indent=2) + '\n', encoding='utf-8')" +if errorlevel 1 ( + echo [ERROR] Failed to write installer selection metadata. + exit /b 1 +) + +echo [OK] Wrote installer selection metadata: %INSTALLER_SELECTION_JSON% +exit /b 0 + + +:trim_var +setlocal EnableDelayedExpansion +set "s=!%~1!" +if not defined s ( + endlocal & set "%~1=" & exit /b 0 +) +for /f "tokens=* delims= " %%Z in ("!s!") do set "s=%%Z" +:trim_var_r +if "!s:~-1!"==" " set "s=!s:~0,-1!" & goto trim_var_r +endlocal & set "%~1=%s%" +exit /b 0 + + +:to_short_path +setlocal +set "in=%~1" +set "out=" +if not defined in ( + endlocal & set "%~2=" & exit /b 0 +) +for %%I in ("%in%") do set "out=%%~sI" +if not defined out set "out=%in%" +endlocal & set "%~2=%out%" +exit /b 0 diff --git a/inspect_tetranerf_cli.py b/inspect_tetranerf_cli.py new file mode 100644 index 0000000000..9fbcf1d5b5 --- /dev/null +++ b/inspect_tetranerf_cli.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +from tetranerf.nerfstudio.registration import tetranerf + + +def try_get(obj, path: str) -> None: + cur = obj + ok = True + for chunk in path.split("."): + if not hasattr(cur, chunk): + ok = False + break + cur = getattr(cur, chunk) + if ok: + print(f"[OK] {path} = {cur!r}") + else: + print(f"[NO] {path}") + + +if __name__ == "__main__": + cfg = tetranerf.config + + candidates = [ + "data", + "output_dir", + "pipeline", + "pipeline.datamanager", + "pipeline.datamanager.data", + "pipeline.datamanager.dataparser", + "pipeline.datamanager.dataparser.data", + "pipeline.datamanager.dataparser.colmap_path", + "pipeline.datamanager.dataparser.colmap-path", + ] + + for c in candidates: + try_get(cfg, c.replace("-", "_")) \ No newline at end of file diff --git a/inspect_tetranerf_registration.py b/inspect_tetranerf_registration.py new file mode 100644 index 0000000000..f41e91ea59 --- /dev/null +++ b/inspect_tetranerf_registration.py @@ -0,0 +1,20 @@ +# inspect_tetranerf_registration.py +import importlib +from pprint import pprint + +mod = importlib.import_module("tetranerf.nerfstudio.registration") + +print("MODULE:", mod.__file__) +print("\nNAMES:") +pprint([x for x in dir(mod) if not x.startswith("_")]) + +for name in dir(mod): + if name.startswith("_"): + continue + obj = getattr(mod, name) + print(f"\n--- {name} ---") + print(type(obj)) + if hasattr(obj, "config"): + print("has .config") + if hasattr(obj, "description"): + print("has .description") \ No newline at end of file diff --git a/install_all_methods.bat b/install_all_methods.bat new file mode 100644 index 0000000000..19ab585a2c --- /dev/null +++ b/install_all_methods.bat @@ -0,0 +1,20 @@ +@echo off +set ROOT=%CD% + +echo ============================== +echo Installing all Nerfstudio methods (editable) +echo ============================== + +for %%D in (*) do ( + if exist "%%D\pyproject.toml" ( + echo. + echo Installing %%D ... + cd %%D + pip install -e . --no-deps + cd %ROOT% + ) +) + +echo. +echo ✅ All editable installs completed +pause \ No newline at end of file diff --git a/install_unix.sh b/install_unix.sh new file mode 100644 index 0000000000..45f2be64cb --- /dev/null +++ b/install_unix.sh @@ -0,0 +1,183 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ============================================================ +# Nerfstudio Custom - Linux/macOS installer +# - Linux: supports CUDA/Torch/tiny-cuda-nn path +# - macOS: installs base package only and skips CUDA-specific parts +# ============================================================ + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$ROOT_DIR" + +DEFAULT_ENV_NAME="nerfstudio" +DEFAULT_PYTHON="3.10" +OS_NAME="$(uname -s)" +INSTALL_MODE="" +ENV_NAME="" +PY_VER="$DEFAULT_PYTHON" +CUDA_PRESET="11.8" +NS_EXTRAS="" + +banner() { + echo + echo "======================================================" + echo " Nerfstudio Custom - Linux/macOS Installer" + echo "======================================================" + echo + echo "Working directory: $PWD" + echo "Detected OS: $OS_NAME" + echo +} + +ask() { + local prompt="$1" + local default="${2:-}" + local value + if [[ -n "$default" ]]; then + read -r -p "$prompt [$default]: " value + echo "${value:-$default}" + else + read -r -p "$prompt: " value + echo "$value" + fi +} + +need_cmd() { + command -v "$1" >/dev/null 2>&1 || { echo "[ERROR] Missing command: $1"; exit 1; } +} + +create_or_activate_env() { + echo "Choose environment mode:" + echo " 1) new conda env" + echo " 2) existing conda env" + echo " 3) new venv" + echo " 4) current python" + read -r -p "Enter choice [1-4]: " mode + + case "$mode" in + 1) + need_cmd conda + INSTALL_MODE="new_conda" + ENV_NAME="$(ask 'New conda env name' "$DEFAULT_ENV_NAME")" + PY_VER="$(ask 'Python version' "$DEFAULT_PYTHON")" + conda create -y -n "$ENV_NAME" "python=$PY_VER" + # shellcheck disable=SC1091 + source "$(conda info --base)/etc/profile.d/conda.sh" + conda activate "$ENV_NAME" + ;; + 2) + need_cmd conda + INSTALL_MODE="existing_conda" + ENV_NAME="$(ask 'Existing conda env name')" + # shellcheck disable=SC1091 + source "$(conda info --base)/etc/profile.d/conda.sh" + conda activate "$ENV_NAME" + ;; + 3) + INSTALL_MODE="new_venv" + ENV_NAME="$(ask 'New venv folder name' "$DEFAULT_ENV_NAME.venv")" + PY_VER="$(ask 'Python command for venv creation' "python3")" + "$PY_VER" -m venv "$ENV_NAME" + # shellcheck disable=SC1091 + source "$ENV_NAME/bin/activate" + ;; + 4) + INSTALL_MODE="current" + ;; + *) + echo "[ERROR] Invalid environment choice."; exit 1 ;; + esac + + python -m pip install --upgrade pip setuptools wheel +} + +choose_cuda_stack() { + if [[ "$OS_NAME" == "Darwin" ]]; then + CUDA_PRESET="cpu" + echo "[INFO] macOS detected. CUDA/tiny-cuda-nn steps will be skipped." + return + fi + + echo + echo "CUDA / Torch preset:" + echo " 1) CUDA 11.8 + Torch 2.1.2" + echo " 2) CUDA 11.7 + Torch 2.0.1" + echo " 3) CPU-only" + read -r -p "Enter choice [1-3]: " choice + case "$choice" in + 1) CUDA_PRESET="11.8" ;; + 2) CUDA_PRESET="11.7" ;; + 3) CUDA_PRESET="cpu" ;; + *) echo "[ERROR] Invalid CUDA choice."; exit 1 ;; + esac +} + +install_torch_and_tcnn() { + if [[ "$CUDA_PRESET" == "11.8" ]]; then + python -m pip install torch==2.1.2+cu118 torchvision==0.16.2+cu118 --extra-index-url https://download.pytorch.org/whl/cu118 + if [[ "$INSTALL_MODE" == *conda* ]]; then + conda install -y -c "nvidia/label/cuda-11.8.0" cuda-toolkit + fi + python -m pip install ninja git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch + elif [[ "$CUDA_PRESET" == "11.7" ]]; then + python -m pip install torch==2.0.1+cu117 torchvision==0.15.2+cu117 --extra-index-url https://download.pytorch.org/whl/cu117 + if [[ "$INSTALL_MODE" == *conda* ]]; then + conda install -y -c "nvidia/label/cuda-11.7.1" cuda-toolkit + fi + python -m pip install ninja git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch + else + python -m pip install torch torchvision + echo "[INFO] Skipping tiny-cuda-nn for CPU/macOS install." + fi +} + +choose_package_flavor() { + echo + echo "Nerfstudio package flavor:" + echo " 1) base" + echo " 2) gen" + echo " 3) dev" + echo " 4) dev,docs" + read -r -p "Enter choice [1-4]: " choice + case "$choice" in + 1) NS_EXTRAS="" ;; + 2) NS_EXTRAS='[gen]' ;; + 3) NS_EXTRAS='[dev]' ;; + 4) NS_EXTRAS='[dev,docs]' ;; + *) echo "[ERROR] Invalid package choice."; exit 1 ;; + esac +} + +install_nerfstudio() { + if [[ -f pyproject.toml ]]; then + python -m pip install -e ".${NS_EXTRAS}" + else + python -m pip install nerfstudio + fi + ns-install-cli +} + +write_notes() { + cat <nul + +if not exist "%PY_SCRIPT%" ( + echo [ERROR] Missing %PY_SCRIPT% + exit /b 1 +) + +call :select_conda_backend +if errorlevel 1 exit /b %errorlevel% +call :select_gpu_arch +if errorlevel 1 exit /b %errorlevel% +call :select_msvc_toolset +if errorlevel 1 exit /b %errorlevel% +call :write_installer_selection_json +if errorlevel 1 exit /b %errorlevel% + +set "LOCK_MODE=no lock found yet" +if exist "%LOCK_DIR%\pip-freeze-all.txt" set "LOCK_MODE=exact dependency re-apply enabled" + +set "HAS_LOCK=0" +if exist "%LOCK_DIR%\pip-freeze-all.txt" set "HAS_LOCK=1" +set "IF_CURRENT_ACTIVE=" +if defined CONDA_PREFIX set "IF_CURRENT_ACTIVE=/2" + +echo ====================================================== +echo Nerfstudio Custom - smart pinned installer +echo Root dir: %ROOT_DIR% +echo Conda mode: %CONDA_MODE% +echo Lock mode: %LOCK_MODE% +echo GPU arch: %CUDA_ARCH% +echo Preferred MSVC: %PREFERRED_MSVC% +echo ====================================================== +echo. +echo Main actions: +echo 1. Fresh setup / create or rebuild an env from deps-lock +echo 2. Sync an existing env to the pinned stack +echo 3. Freeze the current env into deps-lock +echo 4. Install / patch extra Nerfstudio methods +echo 5. Doctor ^(recommended for troubleshooting^) +echo 6. Advanced / fallback +set /p "CHOICE=Enter choice [1-6, default 1]: " +if not defined CHOICE set "CHOICE=1" + +call :clear_rocm_env + +if "%CHOICE%"=="1" goto :mode_fresh_setup +if "%CHOICE%"=="2" goto :mode_sync_existing +if "%CHOICE%"=="3" goto :mode_export +if "%CHOICE%"=="4" goto :mode_extras +if "%CHOICE%"=="5" goto :mode_doctor +if "%CHOICE%"=="6" goto :mode_advanced + +echo [ERROR] Invalid choice. +exit /b 1 + +:mode_fresh_setup +if "%HAS_LOCK%"=="0" ( + echo [WARN] No deps-lock found yet. + echo [INFO] A fresh setup needs an existing lock. Switching to freeze/export. + goto :mode_export +) +set "TARGET_CONDA_MODE=%CONDA_MODE%" +set /p "TARGET_CONDA_MODE=Create env into which conda backend? [portable/system/current, default %CONDA_MODE%]: " +if not defined TARGET_CONDA_MODE set "TARGET_CONDA_MODE=%CONDA_MODE%" +call :resolve_named_conda_backend "%TARGET_CONDA_MODE%" +if errorlevel 1 exit /b %errorlevel% +set "CREATE_CONDA_EXE=%RESOLVED_CONDA_EXE%" +set "CREATE_PYTHON_EXE=%RESOLVED_PYTHON_EXE%" +set "ENV_NAME=" +set /p "ENV_NAME=Target env name [nerfstudio-portable]: " +if not defined ENV_NAME set "ENV_NAME=nerfstudio-portable" +set "REBUILD_CONFIRM=" +set /p "REBUILD_CONFIRM=If the env already exists, rebuild it from the lock? [Y/n]: " +if /I not "%REBUILD_CONFIRM%"=="N" ( + echo [INFO] Rebuilding/creating %ENV_NAME% from deps-lock... +) else ( + echo [INFO] Creating %ENV_NAME% from deps-lock if missing... +) +"%CREATE_PYTHON_EXE%" "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CREATE_CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" create --env-name "%ENV_NAME%" +set "_RC=%errorlevel%" +if not "%_RC%"=="0" exit /b %_RC% +call :prompt_and_run_extras "%ENV_NAME%" +if errorlevel 1 exit /b %errorlevel% +call :prompt_and_run_doctor_in_env "%ENV_NAME%" +exit /b %errorlevel% + +:mode_sync_existing +if "%HAS_LOCK%"=="0" ( + echo [ERROR] No deps-lock found. Freeze/export first. + exit /b 1 +) +set "SYNC_KIND=" +echo. +echo Sync target: +echo 1. Named conda env +if defined CONDA_PREFIX echo 2. Current active shell / Python +set /p "SYNC_KIND=Choose sync target [1%IF_CURRENT_ACTIVE%, default 1]: " +if not defined SYNC_KIND set "SYNC_KIND=1" +if "%SYNC_KIND%"=="2" goto :mode_repin_current +set "ENV_NAME=" +set /p "ENV_NAME=Existing conda env name to sync: " +if not defined ENV_NAME ( + echo [ERROR] No env name provided. + exit /b 1 +) +call :run_in_conda_env "%ENV_NAME%" python "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" repin --skip-conda +set "_RC=%errorlevel%" +if not "%_RC%"=="0" exit /b %_RC% +call :prompt_and_run_extras "%ENV_NAME%" +if errorlevel 1 exit /b %errorlevel% +call :prompt_and_run_doctor_in_env "%ENV_NAME%" +exit /b %errorlevel% + +:mode_advanced +echo. +echo Advanced actions: +echo 1. Check current env against lock +echo 2. Force full conda + pip repin for a named env +echo 3. Repin current shell / Python only +echo 4. Fall back to original install_windows_full.bat +echo 5. Cancel +set /p "ADV_CHOICE=Enter advanced choice [1-5, default 5]: " +if not defined ADV_CHOICE set "ADV_CHOICE=5" +if "%ADV_CHOICE%"=="1" goto :mode_check +if "%ADV_CHOICE%"=="2" goto :mode_repin_existing +if "%ADV_CHOICE%"=="3" goto :mode_repin_current +if "%ADV_CHOICE%"=="4" goto :mode_fallback +exit /b 0 + +:mode_export +if "%CHOICE%"=="2" goto :mode_create +if "%CHOICE%"=="3" goto :mode_repin_existing +if "%CHOICE%"=="4" goto :mode_repin_current +if "%CHOICE%"=="5" goto :mode_check +if "%CHOICE%"=="6" goto :mode_extras +if "%CHOICE%"=="7" goto :mode_doctor +if "%CHOICE%"=="8" goto :mode_fallback + +echo [ERROR] Invalid choice. +exit /b 1 + +:mode_export +call :prompt_and_run_doctor_in_env +set "_DOC_ENV_NAME=%~1" +if not exist "%DOCTOR_BAT%" exit /b 0 +set "RUN_DOC=" +set /p "RUN_DOC=Run doctor now for %_DOC_ENV_NAME%? [Y/n]: " +if /I "%RUN_DOC%"=="N" exit /b 0 +call :run_in_conda_env "%_DOC_ENV_NAME%" call "%DOCTOR_BAT%" +exit /b %errorlevel% + +:maybe_activate_env_for_export +if errorlevel 1 exit /b %errorlevel% +"%PYTHON_EXE%" "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" export +exit /b %errorlevel% + +:mode_create +set "TARGET_CONDA_MODE=%CONDA_MODE%" +set /p "TARGET_CONDA_MODE=Create env into which conda backend? [portable/system/current, default %CONDA_MODE%]: " +if not defined TARGET_CONDA_MODE set "TARGET_CONDA_MODE=%CONDA_MODE%" +call :resolve_named_conda_backend "%TARGET_CONDA_MODE%" +if errorlevel 1 exit /b %errorlevel% +set "CREATE_CONDA_EXE=%RESOLVED_CONDA_EXE%" +set "CREATE_PYTHON_EXE=%RESOLVED_PYTHON_EXE%" +set "ENV_NAME=" +set /p "ENV_NAME=New conda env name [nerfstudio-portable]: " +if not defined ENV_NAME set "ENV_NAME=nerfstudio-portable" +"%CREATE_PYTHON_EXE%" "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CREATE_CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" create --env-name "%ENV_NAME%" +set "_RC=%errorlevel%" +if not "%_RC%"=="0" exit /b %_RC% +call :prompt_and_run_extras "%ENV_NAME%" +if errorlevel 1 exit /b %errorlevel% + +:mode_repin_existing +set "ENV_NAME=" +set /p "ENV_NAME=Existing conda env name to repin: " +if not defined ENV_NAME ( + echo [ERROR] No env name provided. + exit /b 1 +) +set "FORCE_CONDA=" +set /p "FORCE_CONDA=Also force full conda restore first? [y/N]: " +if /I "%FORCE_CONDA%"=="Y" ( + call :run_in_conda_env "%ENV_NAME%" python "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" repin --force-conda +) else ( + call :run_in_conda_env "%ENV_NAME%" python "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" repin --skip-conda +) +set "_RC=%errorlevel%" +if not "%_RC%"=="0" exit /b %_RC% +call :prompt_and_run_extras "%ENV_NAME%" +if errorlevel 1 exit /b %errorlevel% + +:mode_repin_current +call :clear_rocm_env +"%PYTHON_EXE%" "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" repin --skip-conda +exit /b %errorlevel% + +:mode_check +"%PYTHON_EXE%" "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" check +exit /b %errorlevel% + +:mode_extras +if not exist "%EXTRAS_BAT%" ( + echo [ERROR] Missing %EXTRAS_BAT% + exit /b 1 +) +set "EXTRAS_ENV_NAME=" +set /p "EXTRAS_ENV_NAME=Extras target env name [leave blank = current shell / extras script default]: " +if defined EXTRAS_ENV_NAME ( + call "%EXTRAS_BAT%" "%EXTRAS_ENV_NAME%" +) else ( + call "%EXTRAS_BAT%" +) +exit /b %errorlevel% + +:mode_doctor +if not exist "%DOCTOR_BAT%" ( + echo [ERROR] Missing %DOCTOR_BAT% + exit /b 1 +) +call "%DOCTOR_BAT%" +exit /b %errorlevel% + +:mode_fallback +if exist "%ORIGINAL_INSTALLER%" ( + call "%ORIGINAL_INSTALLER%" + exit /b %errorlevel% +) +echo [ERROR] Original installer not found: %ORIGINAL_INSTALLER% +exit /b 1 + +:maybe_activate_env_for_export +if defined CONDA_PREFIX ( + echo [INFO] Current active conda env detected: + echo %CONDA_PREFIX% + set "USE_ACTIVE=" + set /p "USE_ACTIVE=Export current active env as-is? [Y/n]: " + if /I "!USE_ACTIVE!"=="N" goto :prompt_export_env_name + exit /b 0 +) +:prompt_export_env_name +set "EXPORT_ENV_NAME=" +set /p "EXPORT_ENV_NAME=Env name to activate before export (leave blank to export selected base): " +if not defined EXPORT_ENV_NAME exit /b 0 +call "%CONDA_BAT%" activate "%EXPORT_ENV_NAME%" +if errorlevel 1 exit /b %errorlevel% +exit /b 0 + +:select_conda_backend +echo. +echo Conda backend mode: +echo 1. portable ^(recommended reproducible project-local .conda^) +echo 2. system ^(existing Anaconda/Miniconda installed on the PC^) +echo 3. current ^(derive from current active CONDA_EXE / PATH^) +set /p "CONDA_MODE_CHOICE=Choose conda backend [1-3, default 1]: " +if not defined CONDA_MODE_CHOICE set "CONDA_MODE_CHOICE=1" +if "%CONDA_MODE_CHOICE%"=="1" call :resolve_named_conda_backend portable +if "%CONDA_MODE_CHOICE%"=="2" call :resolve_named_conda_backend system +if "%CONDA_MODE_CHOICE%"=="3" call :resolve_named_conda_backend current +if errorlevel 1 exit /b %errorlevel% +if not defined RESOLVED_CONDA_MODE ( + echo [ERROR] Invalid conda backend choice. + exit /b 1 +) +set "CONDA_MODE=%RESOLVED_CONDA_MODE%" +set "SELECTED_CONDA_ROOT=%RESOLVED_CONDA_ROOT%" +set "CONDA_EXE=%RESOLVED_CONDA_EXE%" +set "CONDA_BAT=%RESOLVED_CONDA_BAT%" +set "PYTHON_EXE=%RESOLVED_PYTHON_EXE%" +exit /b 0 + +:resolve_named_conda_backend +set "REQ_MODE=%~1" +set "RESOLVED_CONDA_MODE=" +set "RESOLVED_CONDA_ROOT=" +set "RESOLVED_CONDA_EXE=" +set "RESOLVED_CONDA_BAT=" +set "RESOLVED_PYTHON_EXE=" +if /I "%REQ_MODE%"=="portable" goto :resolve_portable +if /I "%REQ_MODE%"=="system" goto :resolve_system +if /I "%REQ_MODE%"=="current" goto :resolve_current +echo [ERROR] Unknown conda backend: %REQ_MODE% +exit /b 1 + +:resolve_portable +if not exist "%PORTABLE_ENV_BAT%" ( + echo [ERROR] Missing portable helper: %PORTABLE_ENV_BAT% + exit /b 1 +) +call "%PORTABLE_ENV_BAT%" +if errorlevel 1 exit /b %errorlevel% +if not defined PORTABLE_CONDA_ROOT if exist "%ROOT_DIR%\.conda\Scripts\conda.exe" set "PORTABLE_CONDA_ROOT=%ROOT_DIR%\.conda" +if not defined PORTABLE_CONDA_ROOT ( + echo [ERROR] PORTABLE_CONDA_ROOT not exported by portable_env.bat + exit /b 1 +) +set "RESOLVED_CONDA_MODE=portable" +set "RESOLVED_CONDA_ROOT=%PORTABLE_CONDA_ROOT%" +set "RESOLVED_CONDA_EXE=%PORTABLE_CONDA_ROOT%\Scripts\conda.exe" +set "RESOLVED_CONDA_BAT=%PORTABLE_CONDA_ROOT%\condabin\conda.bat" +set "RESOLVED_PYTHON_EXE=%PORTABLE_CONDA_ROOT%\python.exe" +goto :validate_resolved_conda + +:resolve_system +call :detect_system_conda_root +if errorlevel 1 exit /b %errorlevel% +set "RESOLVED_CONDA_MODE=system" +set "RESOLVED_CONDA_ROOT=%SYSTEM_CONDA_ROOT%" +set "RESOLVED_CONDA_EXE=%SYSTEM_CONDA_ROOT%\Scripts\conda.exe" +set "RESOLVED_CONDA_BAT=%SYSTEM_CONDA_ROOT%\condabin\conda.bat" +set "RESOLVED_PYTHON_EXE=%SYSTEM_CONDA_ROOT%\python.exe" +goto :validate_resolved_conda + +:resolve_current +set "CUR_CONDA_EXE=" +if defined CONDA_EXE ( + set "CUR_CONDA_EXE=%CONDA_EXE%" +) else ( + for /f "delims=" %%I in ('where conda.exe 2^>nul') do if not defined CUR_CONDA_EXE set "CUR_CONDA_EXE=%%I" +) +if not defined CUR_CONDA_EXE ( + echo [ERROR] Could not detect a current conda.exe from active shell or PATH. + exit /b 1 +) +for %%I in ("!CUR_CONDA_EXE!") do set "CUR_CONDA_SCRIPTS=%%~dpI" +for %%I in ("!CUR_CONDA_SCRIPTS!..") do set "CUR_CONDA_ROOT=%%~fI" +set "RESOLVED_CONDA_MODE=current" +set "RESOLVED_CONDA_ROOT=!CUR_CONDA_ROOT!" +set "RESOLVED_CONDA_EXE=!CUR_CONDA_ROOT!\Scripts\conda.exe" +set "RESOLVED_CONDA_BAT=!CUR_CONDA_ROOT!\condabin\conda.bat" +set "RESOLVED_PYTHON_EXE=!CUR_CONDA_ROOT!\python.exe" +goto :validate_resolved_conda + +:validate_resolved_conda +if not exist "%RESOLVED_CONDA_EXE%" ( + echo [ERROR] Conda executable not found: %RESOLVED_CONDA_EXE% + exit /b 1 +) +if not exist "%RESOLVED_CONDA_BAT%" ( + echo [ERROR] Conda activation script not found: %RESOLVED_CONDA_BAT% + exit /b 1 +) +if not exist "%RESOLVED_PYTHON_EXE%" ( + echo [ERROR] Python executable not found: %RESOLVED_PYTHON_EXE% + exit /b 1 +) +exit /b 0 + +:clear_rocm_env +set "ROCM_HOME=" +set "ROCM_PATH=" +set "HIP_HOME=" +set "HIP_PATH=" +set "HCC_HOME=" +set "HIP_PATH_57=" +set "HIP_DEVICE_LIB_PATH=" +set "PYTORCH_ROCM_ARCH=" +exit /b 0 + +:run_in_conda_env +set "_NS_ENV_NAME=%~1" +if not defined _NS_ENV_NAME ( + echo [ERROR] Missing env name for activation. + exit /b 1 +) +shift + +set "_NS_CMD=" +:run_in_conda_env_collect +if "%~1"=="" goto :run_in_conda_env_exec +set "_NS_CMD=!_NS_CMD! "%~1"" +shift +goto :run_in_conda_env_collect + +:run_in_conda_env_exec +if not defined _NS_CMD ( + echo [ERROR] Missing command for activated conda env. + exit /b 1 +) + +call :clear_rocm_env +call "%CONDA_BAT%" activate "%_NS_ENV_NAME%" +if errorlevel 1 exit /b %errorlevel% + +call %_NS_CMD% +set "_NS_RC=%errorlevel%" + +call conda deactivate >nul 2>nul +exit /b %_NS_RC% + +:detect_system_conda_root +set "SYSTEM_CONDA_ROOT=" +if defined CONDA_EXE ( + echo %CONDA_EXE% | find /I "%ROOT_DIR%\.conda" >nul + if errorlevel 1 ( + for %%I in ("%CONDA_EXE%") do set "_sys_scripts=%%~dpI" + for %%I in ("!_sys_scripts!..") do set "SYSTEM_CONDA_ROOT=%%~fI" + ) +) +if not defined SYSTEM_CONDA_ROOT for /f "delims=" %%I in ('where conda.exe 2^>nul') do ( + echo %%I | find /I "%ROOT_DIR%\.conda" >nul + if errorlevel 1 if not defined SYSTEM_CONDA_ROOT ( + for %%J in ("%%I") do set "_sys_scripts=%%~dpJ" + for %%J in ("!_sys_scripts!..") do set "SYSTEM_CONDA_ROOT=%%~fJ" + ) +) +if not defined SYSTEM_CONDA_ROOT if exist "%UserProfile%\miniconda3\Scripts\conda.exe" set "SYSTEM_CONDA_ROOT=%UserProfile%\miniconda3" +if not defined SYSTEM_CONDA_ROOT if exist "%UserProfile%\anaconda3\Scripts\conda.exe" set "SYSTEM_CONDA_ROOT=%UserProfile%\anaconda3" +if not defined SYSTEM_CONDA_ROOT ( + echo [ERROR] Could not find a system conda installation. + exit /b 1 +) +exit /b 0 + +:select_gpu_arch +set "GPU_NAME=unknown" +set "CUDA_ARCH=" +set "TCNN_CUDA_ARCHITECTURES=" +echo. +echo GPU arch mode: +echo 1. Auto-detect from nvidia-smi +echo 2. Manual entry +echo 3. Use existing TCNN_CUDA_ARCHITECTURES if already set +set /p "GPU_MODE=Choose GPU arch mode [1-3, default 1]: " +if not defined GPU_MODE set "GPU_MODE=1" +if "%GPU_MODE%"=="1" goto :gpu_auto +if "%GPU_MODE%"=="2" goto :gpu_manual +if "%GPU_MODE%"=="3" goto :gpu_existing +echo [ERROR] Invalid GPU mode. +exit /b 1 +:gpu_existing +if defined TCNN_CUDA_ARCHITECTURES ( + set "CUDA_ARCH=%TCNN_CUDA_ARCHITECTURES%" + set "GPU_NAME=env" + exit /b 0 +) +echo [WARN] TCNN_CUDA_ARCHITECTURES was not already set. Falling back to auto-detect. +goto :gpu_auto +:gpu_auto +for /f "usebackq delims=" %%G in (`nvidia-smi --query-gpu=name --format=csv,noheader 2^>nul`) do if /I "!GPU_NAME!"=="unknown" set "GPU_NAME=%%G" +call :map_gpu_to_arch "%GPU_NAME%" +if not defined CUDA_ARCH goto :gpu_manual_default +set "TCNN_CUDA_ARCHITECTURES=%CUDA_ARCH%" +exit /b 0 +:gpu_manual_default +set "GPU_NAME=manual" +set /p "CUDA_ARCH=Enter CUDA arch [default 86 for RTX 3090]: " +if not defined CUDA_ARCH set "CUDA_ARCH=86" +set "TCNN_CUDA_ARCHITECTURES=%CUDA_ARCH%" +exit /b 0 +:gpu_manual +set "GPU_NAME=manual" +set /p "CUDA_ARCH=Enter CUDA arch (75, 80, 86, 89, 90, 120 ...): " +if not defined CUDA_ARCH ( + echo [ERROR] No CUDA arch provided. + exit /b 1 +) +set "TCNN_CUDA_ARCHITECTURES=%CUDA_ARCH%" +exit /b 0 +:map_gpu_to_arch +set "GPU_LABEL=%~1" +set "CUDA_ARCH=" +echo %GPU_LABEL% | find /I "3090" >nul && set "CUDA_ARCH=86" +echo %GPU_LABEL% | find /I "3080" >nul && set "CUDA_ARCH=86" +echo %GPU_LABEL% | find /I "3070" >nul && set "CUDA_ARCH=86" +echo %GPU_LABEL% | find /I "3060" >nul && set "CUDA_ARCH=86" +echo %GPU_LABEL% | find /I "4090" >nul && set "CUDA_ARCH=89" +echo %GPU_LABEL% | find /I "4080" >nul && set "CUDA_ARCH=89" +echo %GPU_LABEL% | find /I "4070" >nul && set "CUDA_ARCH=89" +echo %GPU_LABEL% | find /I "A100" >nul && set "CUDA_ARCH=80" +echo %GPU_LABEL% | find /I "H100" >nul && set "CUDA_ARCH=90" +exit /b 0 + +:select_msvc_toolset +set "PREFERRED_MSVC=" +echo. +echo Preferred MSVC toolset: +echo 1. auto ^(prefer 14.38 if found, else best compatible^) +echo 2. 14.38 ^(force VS2022 v143 14.38 toolset if installed^) +echo 3. 14 ^(any 14.x compatible MSVC^) +echo 4. system ^(do not force; use current/default MSVC on PATH^) +set /p "MSVC_CHOICE=Choose preferred MSVC toolset [1-4, default 1]: " +if not defined MSVC_CHOICE set "MSVC_CHOICE=1" + +if "%MSVC_CHOICE%"=="1" set "PREFERRED_MSVC=auto" +if "%MSVC_CHOICE%"=="2" set "PREFERRED_MSVC=14.38" +if "%MSVC_CHOICE%"=="3" set "PREFERRED_MSVC=14" +if "%MSVC_CHOICE%"=="4" set "PREFERRED_MSVC=system" + +if not defined PREFERRED_MSVC ( + echo [ERROR] Invalid MSVC choice. + exit /b 1 +) + +if not exist "%LOCK_DIR%" mkdir "%LOCK_DIR%" 2>nul + +> "%MSVC_TOOLSET_LIST_FILE%" echo Detected MSVC toolsets: +for %%R in ( + "%ProgramFiles%\Microsoft Visual Studio\2022\BuildTools" + "%ProgramFiles%\Microsoft Visual Studio\2022\Community" + "%ProgramFiles%\Microsoft Visual Studio\2022\Professional" + "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\Community" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\Professional" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\Enterprise" +) do ( + if exist "%%~R\VC\Tools\MSVC" ( + for /d %%T in ("%%~R\VC\Tools\MSVC\*") do ( + >> "%MSVC_TOOLSET_LIST_FILE%" echo %%~nxT ^| %%~R + ) + ) +) + +if exist "%MSVC_TOOLSET_LIST_FILE%" type "%MSVC_TOOLSET_LIST_FILE%" +exit /b 0 + +:write_installer_selection_json +if not exist "%LOCK_DIR%" mkdir "%LOCK_DIR%" 2>nul +if not exist "%LOCK_DIR%" ( + echo [ERROR] Unable to create lock directory: %LOCK_DIR% + exit /b 1 +) + +set "MSVC_HINT=" +set "MSVC_INSTALL_HINT=" +set "FIRST_MSVC_HINT=" +set "FIRST_MSVC_INSTALL_HINT=" + +if exist "%MSVC_TOOLSET_LIST_FILE%" ( + for /f "usebackq tokens=1,* delims=|" %%A in ("%MSVC_TOOLSET_LIST_FILE%") do ( + set "MSVC_VER=%%~A" + set "MSVC_LOC=%%~B" + call :trim_var MSVC_VER + call :trim_var MSVC_LOC + + if defined MSVC_VER if defined MSVC_LOC ( + if /I not "!MSVC_VER!"=="Detected MSVC toolsets:" ( + if not defined FIRST_MSVC_HINT ( + set "FIRST_MSVC_HINT=!MSVC_VER!" + set "FIRST_MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + + if /I "%PREFERRED_MSVC%"=="14.38" ( + echo(!MSVC_VER!| findstr /b /c:"14.38" >nul + if not errorlevel 1 if not defined MSVC_HINT ( + set "MSVC_HINT=!MSVC_VER!" + set "MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + ) + + if /I "%PREFERRED_MSVC%"=="14" ( + echo(!MSVC_VER!| findstr /b /c:"14." >nul + if not errorlevel 1 if not defined MSVC_HINT ( + set "MSVC_HINT=!MSVC_VER!" + set "MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + ) + + if /I "%PREFERRED_MSVC%"=="auto" ( + echo(!MSVC_VER!| findstr /b /c:"14.38" >nul + if not errorlevel 1 if not defined MSVC_HINT ( + set "MSVC_HINT=!MSVC_VER!" + set "MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + ) + ) + ) + ) +) + +if /I "%PREFERRED_MSVC%"=="auto" ( + if not defined MSVC_HINT ( + set "MSVC_HINT=%FIRST_MSVC_HINT%" + set "MSVC_INSTALL_HINT=%FIRST_MSVC_INSTALL_HINT%" + ) +) + +if /I "%PREFERRED_MSVC%"=="system" ( + set "MSVC_HINT=system" + set "MSVC_INSTALL_HINT=" +) + +if /I not "%PREFERRED_MSVC%"=="auto" if /I not "%PREFERRED_MSVC%"=="system" ( + if not defined MSVC_HINT set "MSVC_HINT=%PREFERRED_MSVC%" +) + +"%PYTHON_EXE%" -c "import json, pathlib; from datetime import datetime, timezone; p=pathlib.Path(r'%INSTALLER_SELECTION_JSON%'); p.parent.mkdir(parents=True, exist_ok=True); data={'cuda_arch': r'%CUDA_ARCH%','tcnn_cuda_architectures': r'%TCNN_CUDA_ARCHITECTURES%','gpu_name': r'%GPU_NAME%','preferred_msvc': r'%PREFERRED_MSVC%','preferred_msvc_mode': r'%PREFERRED_MSVC%','selected_msvc_toolset_hint': r'%MSVC_HINT%','selected_msvc_installation_hint': r'%MSVC_INSTALL_HINT%','conda_mode': r'%CONDA_MODE%','conda_root': r'%SELECTED_CONDA_ROOT%','written_utc': datetime.now(timezone.utc).isoformat()}; p.write_text(json.dumps(data, indent=2) + '\n', encoding='utf-8')" +if errorlevel 1 ( + echo [ERROR] Failed to write installer selection metadata. + exit /b 1 +) + +echo [OK] Wrote installer selection metadata: %INSTALLER_SELECTION_JSON% +exit /b 0 + +:prompt_and_run_extras +set "_EXTRAS_ENV=%~1" +if not defined _EXTRAS_ENV exit /b 0 + +set "INSTALL_EXTRAS_NOW=" +set /p "INSTALL_EXTRAS_NOW=Install extra NeRF methods now? [y/N]: " +call :trim_var INSTALL_EXTRAS_NOW + +if /I not "%INSTALL_EXTRAS_NOW%"=="Y" exit /b 0 + +if not exist "%EXTRAS_BAT%" ( + echo [ERROR] Missing %EXTRAS_BAT% + exit /b 1 +) + +echo [INFO] Launching extras installer for env: %_EXTRAS_ENV% +call "%EXTRAS_BAT%" "%_EXTRAS_ENV%" +exit /b %errorlevel% + +:trim_var +setlocal EnableDelayedExpansion +set "s=!%~1!" +if not defined s ( + endlocal & set "%~1=" & exit /b 0 +) +for /f "tokens=* delims= " %%Z in ("!s!") do set "s=%%Z" +:trim_var_r +if "!s:~-1!"==" " set "s=!s:~0,-1!" & goto trim_var_r +endlocal & set "%~1=%s%" +exit /b 0 diff --git a/install_windows_full_pinned.bat.bak b/install_windows_full_pinned.bat.bak new file mode 100644 index 0000000000..c4ac511c12 --- /dev/null +++ b/install_windows_full_pinned.bat.bak @@ -0,0 +1,550 @@ +@echo off +setlocal EnableExtensions EnableDelayedExpansion +cd /d "%~dp0" + +set "ROOT_DIR=%CD%" +set "LOCK_DIR=%ROOT_DIR%\deps-lock" +set "PY_SCRIPT=%ROOT_DIR%\deps_lock.py" +set "ORIGINAL_INSTALLER=%ROOT_DIR%\install_windows_full.bat" +set "PORTABLE_ENV_BAT=%ROOT_DIR%\portable_env.bat" +set "EXTRAS_BAT=%ROOT_DIR%\extras_portable_manager.bat" +set "DOCTOR_BAT=%ROOT_DIR%\doctor.bat" +set "INSTALLER_SELECTION_JSON=%LOCK_DIR%\installer-selection.json" +set "MSVC_TOOLSET_LIST_FILE=%LOCK_DIR%\msvc-toolsets.txt" +set "MSVC_SELECTED_LOG_FILE=%LOCK_DIR%\msvc-selected.txt" +if not exist "%LOCK_DIR%" mkdir "%LOCK_DIR%" 2>nul + +if not exist "%PY_SCRIPT%" ( + echo [ERROR] Missing %PY_SCRIPT% + exit /b 1 +) + +call :select_conda_backend +if errorlevel 1 exit /b %errorlevel% +call :select_gpu_arch +if errorlevel 1 exit /b %errorlevel% +call :select_msvc_toolset +if errorlevel 1 exit /b %errorlevel% +call :write_installer_selection_json +if errorlevel 1 exit /b %errorlevel% + +set "LOCK_MODE=no lock found yet" +if exist "%LOCK_DIR%\pip-freeze-all.txt" set "LOCK_MODE=exact dependency re-apply enabled" + +echo ====================================================== +echo Nerfstudio Custom - pinned installer +echo Root dir: %ROOT_DIR% +echo Lock dir: %LOCK_DIR% +echo Conda mode: %CONDA_MODE% +echo Conda root: %SELECTED_CONDA_ROOT% +echo Conda exe: %CONDA_EXE% +echo Lock mode: %LOCK_MODE% +echo GPU name: %GPU_NAME% +echo CUDA arch: %CUDA_ARCH% +echo TCNN_CUDA_ARCHITECTURES: %TCNN_CUDA_ARCHITECTURES% +echo Preferred MSVC mode: %PREFERRED_MSVC% +echo Available toolsets log: %MSVC_TOOLSET_LIST_FILE% +echo Bootstrap result log: %MSVC_SELECTED_LOG_FILE% +echo ====================================================== +echo. +echo Choose mode: +echo 1. EXPORT current or selected conda env into deps-lock +echo 2. CREATE NEW conda env from deps-lock +echo 3. REPIN EXISTING conda env to deps-lock (default: pip-layer only) +echo 4. REPIN CURRENT Python/venv to pip lock only +echo 5. CHECK current env against lock +echo 6. INSTALL / PATCH EXTRA METHODS into an env +echo 7. RUN DOCTOR +echo 8. FALL BACK to original install_windows_full.bat +set /p "CHOICE=Enter choice [1-8]: " + +call :clear_rocm_env + +if "%CHOICE%"=="1" goto :mode_export +if "%CHOICE%"=="2" goto :mode_create +if "%CHOICE%"=="3" goto :mode_repin_existing +if "%CHOICE%"=="4" goto :mode_repin_current +if "%CHOICE%"=="5" goto :mode_check +if "%CHOICE%"=="6" goto :mode_extras +if "%CHOICE%"=="7" goto :mode_doctor +if "%CHOICE%"=="8" goto :mode_fallback + +echo [ERROR] Invalid choice. +exit /b 1 + +:mode_export +call :maybe_activate_env_for_export +if errorlevel 1 exit /b %errorlevel% +"%PYTHON_EXE%" "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" export +exit /b %errorlevel% + +:mode_create +set "TARGET_CONDA_MODE=%CONDA_MODE%" +set /p "TARGET_CONDA_MODE=Create env into which conda backend? [portable/system/current, default %CONDA_MODE%]: " +if not defined TARGET_CONDA_MODE set "TARGET_CONDA_MODE=%CONDA_MODE%" +call :resolve_named_conda_backend "%TARGET_CONDA_MODE%" +if errorlevel 1 exit /b %errorlevel% +set "CREATE_CONDA_EXE=%RESOLVED_CONDA_EXE%" +set "CREATE_PYTHON_EXE=%RESOLVED_PYTHON_EXE%" +set "ENV_NAME=" +set /p "ENV_NAME=New conda env name [nerfstudio-portable]: " +if not defined ENV_NAME set "ENV_NAME=nerfstudio-portable" +"%CREATE_PYTHON_EXE%" "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CREATE_CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" create --env-name "%ENV_NAME%" +set "_RC=%errorlevel%" +if not "%_RC%"=="0" exit /b %_RC% +call :prompt_and_run_extras "%ENV_NAME%" +if errorlevel 1 exit /b %errorlevel% + +:mode_repin_existing +set "ENV_NAME=" +set /p "ENV_NAME=Existing conda env name to repin: " +if not defined ENV_NAME ( + echo [ERROR] No env name provided. + exit /b 1 +) +set "FORCE_CONDA=" +set /p "FORCE_CONDA=Also force full conda restore first? [y/N]: " +if /I "%FORCE_CONDA%"=="Y" ( + call :run_in_conda_env "%ENV_NAME%" python "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" repin --force-conda +) else ( + call :run_in_conda_env "%ENV_NAME%" python "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" repin --skip-conda +) +set "_RC=%errorlevel%" +if not "%_RC%"=="0" exit /b %_RC% +call :prompt_and_run_extras "%ENV_NAME%" +if errorlevel 1 exit /b %errorlevel% + +:mode_repin_current +call :clear_rocm_env +"%PYTHON_EXE%" "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" repin --skip-conda +exit /b %errorlevel% + +:mode_check +"%PYTHON_EXE%" "%PY_SCRIPT%" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" --msvc-mode "%PREFERRED_MSVC%" check +exit /b %errorlevel% + +:mode_extras +if not exist "%EXTRAS_BAT%" ( + echo [ERROR] Missing %EXTRAS_BAT% + exit /b 1 +) +set "EXTRAS_ENV_NAME=" +set /p "EXTRAS_ENV_NAME=Extras target env name [leave blank = current shell / extras script default]: " +if defined EXTRAS_ENV_NAME ( + call "%EXTRAS_BAT%" "%EXTRAS_ENV_NAME%" +) else ( + call "%EXTRAS_BAT%" +) +exit /b %errorlevel% + +:mode_doctor +if not exist "%DOCTOR_BAT%" ( + echo [ERROR] Missing %DOCTOR_BAT% + exit /b 1 +) +call "%DOCTOR_BAT%" +exit /b %errorlevel% + +:mode_fallback +if exist "%ORIGINAL_INSTALLER%" ( + call "%ORIGINAL_INSTALLER%" + exit /b %errorlevel% +) +echo [ERROR] Original installer not found: %ORIGINAL_INSTALLER% +exit /b 1 + +:maybe_activate_env_for_export +if defined CONDA_PREFIX ( + echo [INFO] Current active conda env detected: + echo %CONDA_PREFIX% + set "USE_ACTIVE=" + set /p "USE_ACTIVE=Export current active env as-is? [Y/n]: " + if /I "!USE_ACTIVE!"=="N" goto :prompt_export_env_name + exit /b 0 +) +:prompt_export_env_name +set "EXPORT_ENV_NAME=" +set /p "EXPORT_ENV_NAME=Env name to activate before export (leave blank to export selected base): " +if not defined EXPORT_ENV_NAME exit /b 0 +call "%CONDA_BAT%" activate "%EXPORT_ENV_NAME%" +if errorlevel 1 exit /b %errorlevel% +exit /b 0 + +:select_conda_backend +echo. +echo Conda backend mode: +echo 1. portable ^(recommended reproducible project-local .conda^) +echo 2. system ^(existing Anaconda/Miniconda installed on the PC^) +echo 3. current ^(derive from current active CONDA_EXE / PATH^) +set /p "CONDA_MODE_CHOICE=Choose conda backend [1-3, default 1]: " +if not defined CONDA_MODE_CHOICE set "CONDA_MODE_CHOICE=1" +if "%CONDA_MODE_CHOICE%"=="1" call :resolve_named_conda_backend portable +if "%CONDA_MODE_CHOICE%"=="2" call :resolve_named_conda_backend system +if "%CONDA_MODE_CHOICE%"=="3" call :resolve_named_conda_backend current +if errorlevel 1 exit /b %errorlevel% +if not defined RESOLVED_CONDA_MODE ( + echo [ERROR] Invalid conda backend choice. + exit /b 1 +) +set "CONDA_MODE=%RESOLVED_CONDA_MODE%" +set "SELECTED_CONDA_ROOT=%RESOLVED_CONDA_ROOT%" +set "CONDA_EXE=%RESOLVED_CONDA_EXE%" +set "CONDA_BAT=%RESOLVED_CONDA_BAT%" +set "PYTHON_EXE=%RESOLVED_PYTHON_EXE%" +exit /b 0 + +:resolve_named_conda_backend +set "REQ_MODE=%~1" +set "RESOLVED_CONDA_MODE=" +set "RESOLVED_CONDA_ROOT=" +set "RESOLVED_CONDA_EXE=" +set "RESOLVED_CONDA_BAT=" +set "RESOLVED_PYTHON_EXE=" +if /I "%REQ_MODE%"=="portable" goto :resolve_portable +if /I "%REQ_MODE%"=="system" goto :resolve_system +if /I "%REQ_MODE%"=="current" goto :resolve_current +echo [ERROR] Unknown conda backend: %REQ_MODE% +exit /b 1 + +:resolve_portable +if not exist "%PORTABLE_ENV_BAT%" ( + echo [ERROR] Missing portable helper: %PORTABLE_ENV_BAT% + exit /b 1 +) +call "%PORTABLE_ENV_BAT%" +if errorlevel 1 exit /b %errorlevel% +if not defined PORTABLE_CONDA_ROOT if exist "%ROOT_DIR%\.conda\Scripts\conda.exe" set "PORTABLE_CONDA_ROOT=%ROOT_DIR%\.conda" +if not defined PORTABLE_CONDA_ROOT ( + echo [ERROR] PORTABLE_CONDA_ROOT not exported by portable_env.bat + exit /b 1 +) +set "RESOLVED_CONDA_MODE=portable" +set "RESOLVED_CONDA_ROOT=%PORTABLE_CONDA_ROOT%" +set "RESOLVED_CONDA_EXE=%PORTABLE_CONDA_ROOT%\Scripts\conda.exe" +set "RESOLVED_CONDA_BAT=%PORTABLE_CONDA_ROOT%\condabin\conda.bat" +set "RESOLVED_PYTHON_EXE=%PORTABLE_CONDA_ROOT%\python.exe" +goto :validate_resolved_conda + +:resolve_system +call :detect_system_conda_root +if errorlevel 1 exit /b %errorlevel% +set "RESOLVED_CONDA_MODE=system" +set "RESOLVED_CONDA_ROOT=%SYSTEM_CONDA_ROOT%" +set "RESOLVED_CONDA_EXE=%SYSTEM_CONDA_ROOT%\Scripts\conda.exe" +set "RESOLVED_CONDA_BAT=%SYSTEM_CONDA_ROOT%\condabin\conda.bat" +set "RESOLVED_PYTHON_EXE=%SYSTEM_CONDA_ROOT%\python.exe" +goto :validate_resolved_conda + +:resolve_current +set "CUR_CONDA_EXE=" +if defined CONDA_EXE ( + set "CUR_CONDA_EXE=%CONDA_EXE%" +) else ( + for /f "delims=" %%I in ('where conda.exe 2^>nul') do if not defined CUR_CONDA_EXE set "CUR_CONDA_EXE=%%I" +) +if not defined CUR_CONDA_EXE ( + echo [ERROR] Could not detect a current conda.exe from active shell or PATH. + exit /b 1 +) +for %%I in ("!CUR_CONDA_EXE!") do set "CUR_CONDA_SCRIPTS=%%~dpI" +for %%I in ("!CUR_CONDA_SCRIPTS!..") do set "CUR_CONDA_ROOT=%%~fI" +set "RESOLVED_CONDA_MODE=current" +set "RESOLVED_CONDA_ROOT=!CUR_CONDA_ROOT!" +set "RESOLVED_CONDA_EXE=!CUR_CONDA_ROOT!\Scripts\conda.exe" +set "RESOLVED_CONDA_BAT=!CUR_CONDA_ROOT!\condabin\conda.bat" +set "RESOLVED_PYTHON_EXE=!CUR_CONDA_ROOT!\python.exe" +goto :validate_resolved_conda + +:validate_resolved_conda +if not exist "%RESOLVED_CONDA_EXE%" ( + echo [ERROR] Conda executable not found: %RESOLVED_CONDA_EXE% + exit /b 1 +) +if not exist "%RESOLVED_CONDA_BAT%" ( + echo [ERROR] Conda activation script not found: %RESOLVED_CONDA_BAT% + exit /b 1 +) +if not exist "%RESOLVED_PYTHON_EXE%" ( + echo [ERROR] Python executable not found: %RESOLVED_PYTHON_EXE% + exit /b 1 +) +exit /b 0 + +:clear_rocm_env +set "ROCM_HOME=" +set "ROCM_PATH=" +set "HIP_HOME=" +set "HIP_PATH=" +set "HCC_HOME=" +set "HIP_PATH_57=" +set "HIP_DEVICE_LIB_PATH=" +set "PYTORCH_ROCM_ARCH=" +exit /b 0 + +:run_in_conda_env +set "_NS_ENV_NAME=%~1" +if not defined _NS_ENV_NAME ( + echo [ERROR] Missing env name for activation. + exit /b 1 +) +shift + +set "_NS_CMD=" +:run_in_conda_env_collect +if "%~1"=="" goto :run_in_conda_env_exec +set "_NS_CMD=!_NS_CMD! "%~1"" +shift +goto :run_in_conda_env_collect + +:run_in_conda_env_exec +if not defined _NS_CMD ( + echo [ERROR] Missing command for activated conda env. + exit /b 1 +) + +call :clear_rocm_env +call "%CONDA_BAT%" activate "%_NS_ENV_NAME%" +if errorlevel 1 exit /b %errorlevel% + +call %_NS_CMD% +set "_NS_RC=%errorlevel%" + +call conda deactivate >nul 2>nul +exit /b %_NS_RC% + +:detect_system_conda_root +set "SYSTEM_CONDA_ROOT=" +if defined CONDA_EXE ( + echo %CONDA_EXE% | find /I "%ROOT_DIR%\.conda" >nul + if errorlevel 1 ( + for %%I in ("%CONDA_EXE%") do set "_sys_scripts=%%~dpI" + for %%I in ("!_sys_scripts!..") do set "SYSTEM_CONDA_ROOT=%%~fI" + ) +) +if not defined SYSTEM_CONDA_ROOT for /f "delims=" %%I in ('where conda.exe 2^>nul') do ( + echo %%I | find /I "%ROOT_DIR%\.conda" >nul + if errorlevel 1 if not defined SYSTEM_CONDA_ROOT ( + for %%J in ("%%I") do set "_sys_scripts=%%~dpJ" + for %%J in ("!_sys_scripts!..") do set "SYSTEM_CONDA_ROOT=%%~fJ" + ) +) +if not defined SYSTEM_CONDA_ROOT if exist "%UserProfile%\miniconda3\Scripts\conda.exe" set "SYSTEM_CONDA_ROOT=%UserProfile%\miniconda3" +if not defined SYSTEM_CONDA_ROOT if exist "%UserProfile%\anaconda3\Scripts\conda.exe" set "SYSTEM_CONDA_ROOT=%UserProfile%\anaconda3" +if not defined SYSTEM_CONDA_ROOT ( + echo [ERROR] Could not find a system conda installation. + exit /b 1 +) +exit /b 0 + +:select_gpu_arch +set "GPU_NAME=unknown" +set "CUDA_ARCH=" +set "TCNN_CUDA_ARCHITECTURES=" +echo. +echo GPU arch mode: +echo 1. Auto-detect from nvidia-smi +echo 2. Manual entry +echo 3. Use existing TCNN_CUDA_ARCHITECTURES if already set +set /p "GPU_MODE=Choose GPU arch mode [1-3, default 1]: " +if not defined GPU_MODE set "GPU_MODE=1" +if "%GPU_MODE%"=="1" goto :gpu_auto +if "%GPU_MODE%"=="2" goto :gpu_manual +if "%GPU_MODE%"=="3" goto :gpu_existing +echo [ERROR] Invalid GPU mode. +exit /b 1 +:gpu_existing +if defined TCNN_CUDA_ARCHITECTURES ( + set "CUDA_ARCH=%TCNN_CUDA_ARCHITECTURES%" + set "GPU_NAME=env" + exit /b 0 +) +echo [WARN] TCNN_CUDA_ARCHITECTURES was not already set. Falling back to auto-detect. +goto :gpu_auto +:gpu_auto +for /f "usebackq delims=" %%G in (`nvidia-smi --query-gpu=name --format=csv,noheader 2^>nul`) do if /I "!GPU_NAME!"=="unknown" set "GPU_NAME=%%G" +call :map_gpu_to_arch "%GPU_NAME%" +if not defined CUDA_ARCH goto :gpu_manual_default +set "TCNN_CUDA_ARCHITECTURES=%CUDA_ARCH%" +exit /b 0 +:gpu_manual_default +set "GPU_NAME=manual" +set /p "CUDA_ARCH=Enter CUDA arch [default 86 for RTX 3090]: " +if not defined CUDA_ARCH set "CUDA_ARCH=86" +set "TCNN_CUDA_ARCHITECTURES=%CUDA_ARCH%" +exit /b 0 +:gpu_manual +set "GPU_NAME=manual" +set /p "CUDA_ARCH=Enter CUDA arch (75, 80, 86, 89, 90, 120 ...): " +if not defined CUDA_ARCH ( + echo [ERROR] No CUDA arch provided. + exit /b 1 +) +set "TCNN_CUDA_ARCHITECTURES=%CUDA_ARCH%" +exit /b 0 +:map_gpu_to_arch +set "GPU_LABEL=%~1" +set "CUDA_ARCH=" +echo %GPU_LABEL% | find /I "3090" >nul && set "CUDA_ARCH=86" +echo %GPU_LABEL% | find /I "3080" >nul && set "CUDA_ARCH=86" +echo %GPU_LABEL% | find /I "3070" >nul && set "CUDA_ARCH=86" +echo %GPU_LABEL% | find /I "3060" >nul && set "CUDA_ARCH=86" +echo %GPU_LABEL% | find /I "4090" >nul && set "CUDA_ARCH=89" +echo %GPU_LABEL% | find /I "4080" >nul && set "CUDA_ARCH=89" +echo %GPU_LABEL% | find /I "4070" >nul && set "CUDA_ARCH=89" +echo %GPU_LABEL% | find /I "A100" >nul && set "CUDA_ARCH=80" +echo %GPU_LABEL% | find /I "H100" >nul && set "CUDA_ARCH=90" +exit /b 0 + +:select_msvc_toolset +set "PREFERRED_MSVC=" +echo. +echo Preferred MSVC toolset: +echo 1. auto ^(prefer 14.38 if found, else best compatible^) +echo 2. 14.38 ^(force VS2022 v143 14.38 toolset if installed^) +echo 3. 14 ^(any 14.x compatible MSVC^) +echo 4. system ^(do not force; use current/default MSVC on PATH^) +set /p "MSVC_CHOICE=Choose preferred MSVC toolset [1-4, default 1]: " +if not defined MSVC_CHOICE set "MSVC_CHOICE=1" + +if "%MSVC_CHOICE%"=="1" set "PREFERRED_MSVC=auto" +if "%MSVC_CHOICE%"=="2" set "PREFERRED_MSVC=14.38" +if "%MSVC_CHOICE%"=="3" set "PREFERRED_MSVC=14" +if "%MSVC_CHOICE%"=="4" set "PREFERRED_MSVC=system" + +if not defined PREFERRED_MSVC ( + echo [ERROR] Invalid MSVC choice. + exit /b 1 +) + +if not exist "%LOCK_DIR%" mkdir "%LOCK_DIR%" 2>nul + +> "%MSVC_TOOLSET_LIST_FILE%" echo Detected MSVC toolsets: +for %%R in ( + "%ProgramFiles%\Microsoft Visual Studio\2022\BuildTools" + "%ProgramFiles%\Microsoft Visual Studio\2022\Community" + "%ProgramFiles%\Microsoft Visual Studio\2022\Professional" + "%ProgramFiles%\Microsoft Visual Studio\2022\Enterprise" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\Community" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\Professional" + "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\Enterprise" +) do ( + if exist "%%~R\VC\Tools\MSVC" ( + for /d %%T in ("%%~R\VC\Tools\MSVC\*") do ( + >> "%MSVC_TOOLSET_LIST_FILE%" echo %%~nxT ^| %%~R + ) + ) +) + +if exist "%MSVC_TOOLSET_LIST_FILE%" type "%MSVC_TOOLSET_LIST_FILE%" +exit /b 0 + +:write_installer_selection_json +if not exist "%LOCK_DIR%" mkdir "%LOCK_DIR%" 2>nul +if not exist "%LOCK_DIR%" ( + echo [ERROR] Unable to create lock directory: %LOCK_DIR% + exit /b 1 +) + +set "MSVC_HINT=" +set "MSVC_INSTALL_HINT=" +set "FIRST_MSVC_HINT=" +set "FIRST_MSVC_INSTALL_HINT=" + +if exist "%MSVC_TOOLSET_LIST_FILE%" ( + for /f "usebackq tokens=1,* delims=|" %%A in ("%MSVC_TOOLSET_LIST_FILE%") do ( + set "MSVC_VER=%%~A" + set "MSVC_LOC=%%~B" + call :trim_var MSVC_VER + call :trim_var MSVC_LOC + + if defined MSVC_VER if defined MSVC_LOC ( + if /I not "!MSVC_VER!"=="Detected MSVC toolsets:" ( + if not defined FIRST_MSVC_HINT ( + set "FIRST_MSVC_HINT=!MSVC_VER!" + set "FIRST_MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + + if /I "%PREFERRED_MSVC%"=="14.38" ( + echo(!MSVC_VER!| findstr /b /c:"14.38" >nul + if not errorlevel 1 if not defined MSVC_HINT ( + set "MSVC_HINT=!MSVC_VER!" + set "MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + ) + + if /I "%PREFERRED_MSVC%"=="14" ( + echo(!MSVC_VER!| findstr /b /c:"14." >nul + if not errorlevel 1 if not defined MSVC_HINT ( + set "MSVC_HINT=!MSVC_VER!" + set "MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + ) + + if /I "%PREFERRED_MSVC%"=="auto" ( + echo(!MSVC_VER!| findstr /b /c:"14.38" >nul + if not errorlevel 1 if not defined MSVC_HINT ( + set "MSVC_HINT=!MSVC_VER!" + set "MSVC_INSTALL_HINT=!MSVC_LOC!" + ) + ) + ) + ) + ) +) + +if /I "%PREFERRED_MSVC%"=="auto" ( + if not defined MSVC_HINT ( + set "MSVC_HINT=%FIRST_MSVC_HINT%" + set "MSVC_INSTALL_HINT=%FIRST_MSVC_INSTALL_HINT%" + ) +) + +if /I "%PREFERRED_MSVC%"=="system" ( + set "MSVC_HINT=system" + set "MSVC_INSTALL_HINT=" +) + +if /I not "%PREFERRED_MSVC%"=="auto" if /I not "%PREFERRED_MSVC%"=="system" ( + if not defined MSVC_HINT set "MSVC_HINT=%PREFERRED_MSVC%" +) + +"%PYTHON_EXE%" -c "import json, pathlib; from datetime import datetime, timezone; p=pathlib.Path(r'%INSTALLER_SELECTION_JSON%'); p.parent.mkdir(parents=True, exist_ok=True); data={'cuda_arch': r'%CUDA_ARCH%','tcnn_cuda_architectures': r'%TCNN_CUDA_ARCHITECTURES%','gpu_name': r'%GPU_NAME%','preferred_msvc': r'%PREFERRED_MSVC%','preferred_msvc_mode': r'%PREFERRED_MSVC%','selected_msvc_toolset_hint': r'%MSVC_HINT%','selected_msvc_installation_hint': r'%MSVC_INSTALL_HINT%','conda_mode': r'%CONDA_MODE%','conda_root': r'%SELECTED_CONDA_ROOT%','written_utc': datetime.now(timezone.utc).isoformat()}; p.write_text(json.dumps(data, indent=2) + '\n', encoding='utf-8')" +if errorlevel 1 ( + echo [ERROR] Failed to write installer selection metadata. + exit /b 1 +) + +echo [OK] Wrote installer selection metadata: %INSTALLER_SELECTION_JSON% +exit /b 0 + +:prompt_and_run_extras +set "_EXTRAS_ENV=%~1" +if not defined _EXTRAS_ENV exit /b 0 + +set "INSTALL_EXTRAS_NOW=" +set /p "INSTALL_EXTRAS_NOW=Install extra NeRF methods now? [y/N]: " +call :trim_var INSTALL_EXTRAS_NOW + +if /I not "%INSTALL_EXTRAS_NOW%"=="Y" exit /b 0 + +if not exist "%EXTRAS_BAT%" ( + echo [ERROR] Missing %EXTRAS_BAT% + exit /b 1 +) + +echo [INFO] Launching extras installer for env: %_EXTRAS_ENV% +call "%EXTRAS_BAT%" "%_EXTRAS_ENV%" +exit /b %errorlevel% + +:trim_var +setlocal EnableDelayedExpansion +set "s=!%~1!" +if not defined s ( + endlocal & set "%~1=" & exit /b 0 +) +for /f "tokens=* delims= " %%Z in ("!s!") do set "s=%%Z" +:trim_var_r +if "!s:~-1!"==" " set "s=!s:~0,-1!" & goto trim_var_r +endlocal & set "%~1=%s%" +exit /b 0 diff --git a/models/.gitkeep b/models/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/nerfstudio.code-workspace b/nerfstudio.code-workspace deleted file mode 100644 index 5e645c9817..0000000000 --- a/nerfstudio.code-workspace +++ /dev/null @@ -1,84 +0,0 @@ -{ - "folders": [ - { - "path": "." - }, - { - "path": "../nerfstudio1.0.3" - }, - { - "path": "../neuralangelo" - }, - { - "path": "../sdfstudio" - } - ], - "settings": { - "javascript.validate.enable": false, - "files.associations": { - "array": "cpp", - "bitset": "cpp", - "string_view": "cpp", - "initializer_list": "cpp", - "utility": "cpp", - "__hash_table": "cpp", - "__split_buffer": "cpp", - "deque": "cpp", - "iterator": "cpp", - "queue": "cpp", - "stack": "cpp", - "string": "cpp", - "unordered_map": "cpp", - "vector": "cpp", - "atomic": "cpp", - "*.tcc": "cpp", - "cctype": "cpp", - "chrono": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "codecvt": "cpp", - "condition_variable": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdint": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "exception": "cpp", - "algorithm": "cpp", - "filesystem": "cpp", - "functional": "cpp", - "memory": "cpp", - "memory_resource": "cpp", - "optional": "cpp", - "ratio": "cpp", - "system_error": "cpp", - "tuple": "cpp", - "type_traits": "cpp", - "fstream": "cpp", - "iomanip": "cpp", - "iosfwd": "cpp", - "iostream": "cpp", - "istream": "cpp", - "limits": "cpp", - "mutex": "cpp", - "new": "cpp", - "ostream": "cpp", - "sstream": "cpp", - "stdexcept": "cpp", - "streambuf": "cpp", - "thread": "cpp", - "typeinfo": "cpp", - "__nullptr": "cpp", - "__config": "cpp", - "__locale": "cpp", - "__bit_reference": "cpp", - "ios": "cpp", - "__atomic": "cpp", - "__node_handle": "cpp" - } - } -} \ No newline at end of file diff --git a/nerfstudio/configs/external_methods.py b/nerfstudio/configs/external_methods.py index fdf1be7429..bf10c62448 100644 --- a/nerfstudio/configs/external_methods.py +++ b/nerfstudio/configs/external_methods.py @@ -305,11 +305,11 @@ class ExternalMethod: For more information visit: https://docs.nerf.studio/nerfology/methods/splatw.html To enable Splatfacto-W, you must install it first by running: - [grey]pip install git+https://github.com/KevinXu02/splatfacto-w"[/grey]""", + [grey]pip install git+https://github.com/BlockFrank/splatfacto-w_reforged"[/grey]""", configurations=[ ("splatfacto-w", "Splatfacto in the wild"), ], - pip_package="git+https://github.com/KevinXu02/splatfacto-w", + pip_package="git+https://github.com/BlockFrank/splatfacto-w_reforged", ) ) diff --git a/nerfstudio/exporter/exporter_utils.py b/nerfstudio/exporter/exporter_utils.py index 3cd1fc2872..f7c16125da 100644 --- a/nerfstudio/exporter/exporter_utils.py +++ b/nerfstudio/exporter/exporter_utils.py @@ -38,8 +38,6 @@ from nerfstudio.utils.rich_utils import CONSOLE, ItersPerSecColumn if TYPE_CHECKING: - # Importing open3d can take ~1 second, so only do it below if we actually - # need it. import open3d as o3d @@ -80,6 +78,90 @@ def get_mesh_from_filename(filename: str, target_num_faces: Optional[int] = None return get_mesh_from_pymeshlab_mesh(mesh) +def _safe_get_train_dataset(pipeline: Pipeline) -> Optional[InputDataset]: + """Best-effort access to the train dataset for custom datamanagers.""" + datamanager = getattr(pipeline, "datamanager", None) + if datamanager is None: + return None + dataset = getattr(datamanager, "train_dataset", None) + if isinstance(dataset, InputDataset): + return dataset + return None + + +def _safe_get_train_raybundle_from_datamanager(pipeline: Pipeline) -> Optional[RayBundle]: + """Try the standard datamanager path first.""" + datamanager = getattr(pipeline, "datamanager", None) + if datamanager is None or not hasattr(datamanager, "next_train"): + return None + + try: + train_out = datamanager.next_train(0) + except Exception: + return None + + ray_bundle: Any = None + if isinstance(train_out, tuple) and len(train_out) >= 1: + ray_bundle = train_out[0] + else: + ray_bundle = train_out + + if isinstance(ray_bundle, RayBundle): + return ray_bundle + return None + + +def _generate_raybundle_from_train_dataset( + pipeline: Pipeline, + camera_idx: int, +) -> Optional[RayBundle]: + """Fallback path for custom datamanagers that do not return a RayBundle in next_train().""" + dataset = _safe_get_train_dataset(pipeline) + if dataset is None: + return None + + cameras = getattr(dataset, "cameras", None) + if cameras is None or len(cameras) == 0: + return None + + camera_idx = int(camera_idx % len(cameras)) + + try: + camera = cameras[camera_idx : camera_idx + 1] + ray_bundle = camera.generate_rays(camera_indices=0) + return ray_bundle.to(pipeline.device) + except Exception: + pass + + try: + ray_bundle = cameras.generate_rays(camera_indices=camera_idx) + return ray_bundle.to(pipeline.device) + except Exception: + return None + + +def _get_next_export_raybundle( + pipeline: Pipeline, + fallback_camera_idx: int, +) -> RayBundle: + """Robustly obtain a RayBundle for exporters, including custom datamanagers.""" + ray_bundle = _safe_get_train_raybundle_from_datamanager(pipeline) + if ray_bundle is not None: + return ray_bundle.to(pipeline.device) + + ray_bundle = _generate_raybundle_from_train_dataset(pipeline, fallback_camera_idx) + if ray_bundle is not None: + return ray_bundle + + datamanager_name = type(getattr(pipeline, "datamanager", None)).__name__ + raise RuntimeError( + "Could not obtain a RayBundle for export. " + f"Datamanager type: {datamanager_name}. " + "This exporter supports standard Nerfstudio datamanagers and best-effort fallback via " + "train_dataset.cameras.generate_rays(...), but both paths failed." + ) + + def generate_point_cloud( pipeline: Pipeline, num_points: int = 1000000, @@ -116,31 +198,40 @@ def generate_point_cloud( TimeRemainingColumn(elapsed_when_finished=True, compact=True), console=CONSOLE, ) + points = [] rgbs = [] normals = [] view_directions = [] + + fallback_camera_idx = 0 + with progress as progress_bar: task = progress_bar.add_task("Generating Point Cloud", total=num_points) + while not progress_bar.finished: normal = None with torch.no_grad(): - ray_bundle, _ = pipeline.datamanager.next_train(0) - assert isinstance(ray_bundle, RayBundle) + ray_bundle = _get_next_export_raybundle(pipeline, fallback_camera_idx) + fallback_camera_idx += 1 outputs = pipeline.model(ray_bundle) + if rgb_output_name not in outputs: CONSOLE.rule("Error", style="red") CONSOLE.print(f"Could not find {rgb_output_name} in the model outputs", justify="center") CONSOLE.print(f"Please set --rgb_output_name to one of: {outputs.keys()}", justify="center") sys.exit(1) + if depth_output_name not in outputs: CONSOLE.rule("Error", style="red") CONSOLE.print(f"Could not find {depth_output_name} in the model outputs", justify="center") CONSOLE.print(f"Please set --depth_output_name to one of: {outputs.keys()}", justify="center") sys.exit(1) + rgba = pipeline.model.get_rgba_image(outputs, rgb_output_name) depth = outputs[depth_output_name] + if normal_output_name is not None: if normal_output_name not in outputs: CONSOLE.rule("Error", style="red") @@ -152,10 +243,10 @@ def generate_point_cloud( "Normal values from method output must be in [0, 1]" ) normal = (normal * 2.0) - 1.0 + point = ray_bundle.origins + ray_bundle.directions * depth view_direction = ray_bundle.directions - # Filter points with opacity lower than 0.5 mask = rgba[..., -1] > 0.5 point = point[mask] view_direction = view_direction[mask] @@ -171,12 +262,20 @@ def generate_point_cloud( if normal is not None: normal = normal[mask] + if point.numel() == 0: + continue + points.append(point) rgbs.append(rgb) view_directions.append(view_direction) if normal is not None: normals.append(normal) + progress.advance(task, point.shape[0]) + + if len(points) == 0: + raise RuntimeError("Point cloud export produced zero valid points.") + points = torch.cat(points, dim=0) rgbs = torch.cat(rgbs, dim=0) view_directions = torch.cat(view_directions, dim=0).cpu() @@ -196,7 +295,6 @@ def generate_point_cloud( if ind is not None: view_directions = view_directions[ind] - # either estimate_normals or normal_output_name, not both if estimate_normals: if normal_output_name is not None: CONSOLE.rule("Error", style="red") @@ -209,11 +307,9 @@ def generate_point_cloud( elif normal_output_name is not None: normals = torch.cat(normals, dim=0) if ind is not None: - # mask out normals for points that were removed with remove_outliers normals = normals[ind] pcd.normals = o3d.utility.Vector3dVector(normals.double().cpu().numpy()) - # re-orient the normals if reorient_normals: normals = torch.from_numpy(np.array(pcd.normals)).float() mask = torch.sum(view_directions * normals, dim=-1) > 0 @@ -304,13 +400,11 @@ def collect_camera_poses_for_dataset( frames: List[Dict[str, Any]] = [] - # new cameras are in cameras, whereas image paths are stored in a private member of the dataset for idx in range(len(cameras)): image_filename = image_filenames[idx] if camera_optimizer is None: transform = cameras.camera_to_worlds[idx].tolist() else: - # print('exporting optimized camera pose for camera %d' % idx) camera = cameras[idx : idx + 1] assert camera.metadata is not None camera.metadata["cam_idx"] = idx @@ -348,7 +442,6 @@ def collect_camera_poses(pipeline: VanillaPipeline) -> Tuple[List[Dict[str, Any] assert isinstance(camera_optimizer, CameraOptimizer) train_frames = collect_camera_poses_for_dataset(train_dataset, camera_optimizer) - # Note: returning original poses, even if --eval-mode=all eval_frames = collect_camera_poses_for_dataset(eval_dataset) - return train_frames, eval_frames + return train_frames, eval_frames \ No newline at end of file diff --git a/nerfstudio/plugins/registry.py b/nerfstudio/plugins/registry.py index f50550f74b..b53b15af72 100644 --- a/nerfstudio/plugins/registry.py +++ b/nerfstudio/plugins/registry.py @@ -16,64 +16,68 @@ Module that keeps all registered plugins and allows for plugin discovery. """ -import importlib -import os -import sys -import typing as t +from __future__ import annotations + +from typing import Dict, Tuple + +from rich.console import Console -from nerfstudio.engine.trainer import TrainerConfig from nerfstudio.plugins.types import MethodSpecification -from nerfstudio.utils.rich_utils import CONSOLE -if sys.version_info < (3, 10): - from importlib_metadata import entry_points -else: +CONSOLE = Console(width=120) + +try: from importlib.metadata import entry_points +except ImportError: + from importlib_metadata import entry_points -def discover_methods() -> t.Tuple[t.Dict[str, TrainerConfig], t.Dict[str, str]]: +def discover_methods() -> Tuple[Dict[str, MethodSpecification], Dict[str, str]]: """ - Discovers all methods registered using the `nerfstudio.method_configs` entrypoint. - And also methods in the NERFSTUDIO_METHOD_CONFIGS environment variable. + Discover external nerfstudio methods via entry points. + + IMPORTANT: + This loader is intentionally resilient: + - broken external methods are skipped + - import/load errors do not crash nerfstudio CLI """ - methods = {} - descriptions = {} + methods: Dict[str, MethodSpecification] = {} + descriptions: Dict[str, str] = {} + discovered_entry_points = entry_points(group="nerfstudio.method_configs") - for name in discovered_entry_points.names: - spec = discovered_entry_points[name].load() + + # Compat for different importlib.metadata return types + try: + names = discovered_entry_points.names + get_ep = lambda name: discovered_entry_points[name] + except AttributeError: + eps_by_name = {ep.name: ep for ep in discovered_entry_points} + names = eps_by_name.keys() + get_ep = lambda name: eps_by_name[name] + + for name in names: + ep = get_ep(name) + + try: + spec = ep.load() + except Exception as exc: + CONSOLE.print( + f"[bold yellow]Warning:[/bold yellow] Skipping external method " + f"[cyan]{name}[/cyan] because it failed to import/load.\n" + f" Entry point: {ep.value}\n" + f" Error: {type(exc).__name__}: {exc}" + ) + continue + if not isinstance(spec, MethodSpecification): CONSOLE.print( - f"[bold yellow]Warning: Could not entry point {spec} as it is not an instance of MethodSpecification" + f"[bold yellow]Warning:[/bold yellow] Skipping external method " + f"[cyan]{name}[/cyan] because loaded object is not a MethodSpecification.\n" + f" Loaded object type: {type(spec).__name__}" ) continue - spec = t.cast(MethodSpecification, spec) - methods[spec.config.method_name] = spec.config - descriptions[spec.config.method_name] = spec.description - if "NERFSTUDIO_METHOD_CONFIGS" in os.environ: - try: - strings = os.environ["NERFSTUDIO_METHOD_CONFIGS"].split(",") - for definition in strings: - if not definition: - continue - name, path = definition.split("=") - CONSOLE.print(f"[bold green]Info: Loading method {name} from environment variable") - module, config_name = path.split(":") - method_config = getattr(importlib.import_module(module), config_name) - - # method_config specified as function or class -> instance - if callable(method_config): - method_config = method_config() - - # check for valid instance type - if not isinstance(method_config, MethodSpecification): - raise TypeError("Method is not an instance of MethodSpecification") - - # save to methods - methods[name] = method_config.config - descriptions[name] = method_config.description - except Exception: - CONSOLE.print_exception() - CONSOLE.print("[bold red]Error: Could not load methods from environment variable NERFSTUDIO_METHOD_CONFIGS") - - return methods, descriptions + methods[name] = spec + descriptions[name] = spec.description + + return methods, descriptions \ No newline at end of file diff --git a/nerfstudio/plugins/registry_dataparser.py b/nerfstudio/plugins/registry_dataparser.py index 6b1e34a0f3..1a13ed4b43 100644 --- a/nerfstudio/plugins/registry_dataparser.py +++ b/nerfstudio/plugins/registry_dataparser.py @@ -30,6 +30,7 @@ from importlib_metadata import entry_points else: from importlib.metadata import entry_points + CONSOLE = Console(width=120) @@ -51,17 +52,33 @@ def discover_dataparsers() -> t.Tuple[t.Dict[str, DataParserConfig], t.Dict[str, """ Discovers all dataparsers registered using the `nerfstudio.dataparser_configs` entrypoint. And also dataparsers in the NERFSTUDIO_DATAPARSER_CONFIGS environment variable. + + Resilient patch: + - broken external dataparsers are skipped with a warning + - one bad plugin no longer kills startup """ dataparsers = {} descriptions = {} discovered_entry_points = entry_points(group="nerfstudio.dataparser_configs") + for name in discovered_entry_points.names: - spec = discovered_entry_points[name].load() + try: + spec = discovered_entry_points[name].load() + except Exception as exc: # pylint: disable=broad-except + CONSOLE.print( + f"[bold yellow]Warning:[/bold yellow] Skipping external dataparser " + f"[cyan]{name}[/cyan] because it failed to import/load.\n" + f" Entry point: {discovered_entry_points[name].value}\n" + f" Error: {type(exc).__name__}: {exc}" + ) + continue + if not isinstance(spec, DataParserSpecification): CONSOLE.print( - f"[bold yellow]Warning: Could not entry point {spec} as it is not an instance of DataParserSpecification" + f"[bold yellow]Warning: Could not load entry point {spec} as it is not an instance of DataParserSpecification" ) continue + spec = t.cast(DataParserSpecification, spec) dataparsers[name] = spec.config descriptions[name] = spec.description @@ -77,15 +94,12 @@ def discover_dataparsers() -> t.Tuple[t.Dict[str, DataParserConfig], t.Dict[str, module, config_name = path.split(":") dataparser_config = getattr(importlib.import_module(module), config_name) - # method_config specified as function or class -> instance if callable(dataparser_config): dataparser_config = dataparser_config() - # check for valid instance type if not isinstance(dataparser_config, DataParserSpecification): raise TypeError("Method is not an instance of DataParserSpecification") - # save to methods dataparsers[name] = dataparser_config.config descriptions[name] = dataparser_config.description except Exception: # pylint: disable=broad-except @@ -94,4 +108,4 @@ def discover_dataparsers() -> t.Tuple[t.Dict[str, DataParserConfig], t.Dict[str, "[bold red]Error: Could not load methods from environment variable NERFSTUDIO_DATAPARSER_CONFIGS" ) - return dataparsers, descriptions + return dataparsers, descriptions \ No newline at end of file diff --git a/nerfstudio/scripts/exporter.py b/nerfstudio/scripts/exporter.py index c26797a5c8..83f8bccf84 100644 --- a/nerfstudio/scripts/exporter.py +++ b/nerfstudio/scripts/exporter.py @@ -137,10 +137,12 @@ def main(self) -> None: validate_pipeline(self.normal_method, self.normal_output_name, pipeline) # Increase the batchsize to speed up the evaluation. - assert isinstance( - pipeline.datamanager, - (VanillaDataManager, ParallelDataManager), - ) + # Relaxed datamanager check for custom pipelines (e.g. splatfacto-w) + if not isinstance(pipeline.datamanager, (VanillaDataManager, ParallelDataManager)): + CONSOLE.print( + "[yellow]Warning: Non-standard datamanager detected. " + "Attempting export with best-effort compatibility." + ) if isinstance(pipeline.datamanager, VanillaDataManager): assert pipeline.datamanager.train_pixel_sampler is not None pipeline.datamanager.train_pixel_sampler.num_rays_per_batch = self.num_rays_per_batch @@ -320,10 +322,12 @@ def main(self) -> None: validate_pipeline(self.normal_method, self.normal_output_name, pipeline) # Increase the batchsize to speed up the evaluation. - assert isinstance( - pipeline.datamanager, - (VanillaDataManager, ParallelDataManager), - ) + # Relaxed datamanager check for custom pipelines (e.g. splatfacto-w) + if not isinstance(pipeline.datamanager, (VanillaDataManager, ParallelDataManager)): + CONSOLE.print( + "[yellow]Warning: Non-standard datamanager detected. " + "Attempting export with best-effort compatibility." + ) if isinstance(pipeline.datamanager, VanillaDataManager): assert pipeline.datamanager.train_pixel_sampler is not None pipeline.datamanager.train_pixel_sampler.num_rays_per_batch = self.num_rays_per_batch @@ -560,9 +564,13 @@ def main(self) -> None: _, pipeline, _, _ = eval_setup(self.load_config, test_mode="inference") - assert isinstance(pipeline.model, SplatfactoModel) + # Accept splatfacto and compatible models + if not isinstance(pipeline.model, SplatfactoModel): + # fallback: detect splat-like models + if not (hasattr(pipeline.model, "means") and hasattr(pipeline.model, "opacities")): + raise AssertionError("Model is not a Gaussian Splatting-compatible model.") - model: SplatfactoModel = pipeline.model + model = pipeline.model # allow custom splatfacto variants filename = self.output_dir / self.output_filename diff --git a/nerfstudio/viewer/export_panel.py b/nerfstudio/viewer/export_panel.py index 2bb3969cd5..ba729bd84c 100644 --- a/nerfstudio/viewer/export_panel.py +++ b/nerfstudio/viewer/export_panel.py @@ -24,7 +24,22 @@ from nerfstudio.models.base_model import Model from nerfstudio.models.splatfacto import SplatfactoModel from nerfstudio.viewer.control_panel import ControlPanel - +from nerfstudio.models.splatfacto import SplatfactoModel +try: + from nerfstudio.models.splatfactow import SplatfactoWModel # your custom model +except: + SplatfactoWModel = None + +def is_gsplat_model(model: Model) -> bool: + """Robust detection of gaussian splatting-like models.""" + if isinstance(model, SplatfactoModel): + return True + + if SplatfactoWModel is not None and isinstance(model, SplatfactoWModel): + return True + + # Future-proof: capability-based fallback + return hasattr(model, "means") and hasattr(model, "opacities") def populate_export_tab( server: viser.ViserServer, @@ -32,7 +47,7 @@ def populate_export_tab( config_path: Path, viewer_model: Model, ) -> None: - viewing_gsplat = isinstance(viewer_model, SplatfactoModel) + viewing_gsplat = is_gsplat_model(viewer_model) if not viewing_gsplat: crop_output = server.gui.add_checkbox("Use Crop", False) diff --git a/nerfstudio_stable_environment_post_zipnerf.yaml b/nerfstudio_stable_environment_post_zipnerf.yaml deleted file mode 100644 index 91fb5ad9d7..0000000000 --- a/nerfstudio_stable_environment_post_zipnerf.yaml +++ /dev/null @@ -1,319 +0,0 @@ -name: nerfstudio_test -channels: - - nvidia/label/cuda-11.8.0 - - defaults - - https://repo.anaconda.com/pkgs/main - - https://repo.anaconda.com/pkgs/r - - https://repo.anaconda.com/pkgs/msys2 -dependencies: - - bzip2=1.0.8=h2bbff1b_6 - - ca-certificates=2025.2.25=haa95532_0 - - cuda-cccl=11.8.89=0 - - cuda-command-line-tools=11.8.0=0 - - cuda-compiler=11.8.0=0 - - cuda-cudart=11.8.89=0 - - cuda-cudart-dev=11.8.89=0 - - cuda-cuobjdump=11.8.86=0 - - cuda-cupti=11.8.87=0 - - cuda-cuxxfilt=11.8.86=0 - - cuda-documentation=11.8.86=0 - - cuda-libraries=11.8.0=0 - - cuda-libraries-dev=11.8.0=0 - - cuda-memcheck=11.8.86=0 - - cuda-nsight-compute=11.8.0=0 - - cuda-nvcc=11.8.89=0 - - cuda-nvdisasm=11.8.86=0 - - cuda-nvml-dev=11.8.86=0 - - cuda-nvprof=11.8.87=0 - - cuda-nvprune=11.8.86=0 - - cuda-nvrtc=11.8.89=0 - - cuda-nvrtc-dev=11.8.89=0 - - cuda-nvtx=11.8.86=0 - - cuda-nvvp=11.8.87=0 - - cuda-profiler-api=11.8.86=0 - - cuda-sanitizer-api=11.8.86=0 - - cuda-toolkit=11.8.0=0 - - cuda-tools=11.8.0=0 - - cuda-visual-tools=11.8.0=0 - - libcublas=11.11.3.6=0 - - libcublas-dev=11.11.3.6=0 - - libcufft=10.9.0.58=0 - - libcufft-dev=10.9.0.58=0 - - libcurand=10.3.0.86=0 - - libcurand-dev=10.3.0.86=0 - - libcusolver=11.4.1.48=0 - - libcusolver-dev=11.4.1.48=0 - - libcusparse=11.7.5.86=0 - - libcusparse-dev=11.7.5.86=0 - - libffi=3.4.4=hd77b12b_1 - - libnpp=11.8.0.86=0 - - libnpp-dev=11.8.0.86=0 - - libnvjpeg=11.9.0.86=0 - - libnvjpeg-dev=11.9.0.86=0 - - nsight-compute=2022.3.0.22=0 - - openssl=3.0.16=h3f729d1_0 - - python=3.10.16=h4607a30_1 - - sqlite=3.45.3=h2bbff1b_0 - - tk=8.6.14=h0416ee5_0 - - vc=14.42=haa95532_4 - - vs2015_runtime=14.42.34433=he0abc0d_4 - - wheel=0.45.1=py310haa95532_0 - - xz=5.6.4=h4754444_1 - - zlib=1.2.13=h8cc25b3_1 - - pip: - - absl-py==2.2.2 - - accelerate==0.19.0 - - annotated-types==0.7.0 - - anyio==4.9.0 - - appdirs==1.4.4 - - argon2-cffi==23.1.0 - - argon2-cffi-bindings==21.2.0 - - arrow==1.3.0 - - asttokens==3.0.0 - - async-lru==2.0.5 - - attrs==25.3.0 - - av==14.3.0 - - babel==2.17.0 - - beautifulsoup4==4.13.3 - - bidict==0.23.1 - - bitsandbytes==0.43.0 - - bleach==6.2.0 - - blinker==1.9.0 - - cachetools==5.5.2 - - certifi==2025.1.31 - - cffi==1.17.1 - - charset-normalizer==3.4.1 - - click==8.1.8 - - colorama==0.4.6 - - colorlog==6.9.0 - - comet-ml==3.49.7 - - comm==0.2.2 - - configargparse==1.7 - - configobj==5.0.9 - - contourpy==1.3.1 - - cryptography==44.0.2 - - cuda-backend==0.0.0 - - cycler==0.12.1 - - dash==3.0.2 - - debugpy==1.8.14 - - decorator==5.2.1 - - defusedxml==0.7.1 - - descartes==1.1.0 - - diffusers==0.16.1 - - dill==0.3.9 - - docker-pycreds==0.4.0 - - docstring-parser==0.16 - - dulwich==0.22.8 - - everett==3.1.0 - - exceptiongroup==1.2.2 - - executing==2.2.0 - - fastjsonschema==2.21.1 - - filelock==3.18.0 - - fire==0.7.0 - - flask==3.0.3 - - fonttools==4.57.0 - - fpsample==0.3.3 - - fqdn==1.5.1 - - fsspec==2025.3.2 - - gdown==5.2.0 - - gin-config==0.5.0 - - gitdb==4.0.12 - - gitpython==3.1.44 - - grpcio==1.71.0 - - gsplat==1.5.0 - - h11==0.14.0 - - h5py==3.13.0 - - httpcore==1.0.8 - - httpx==0.28.1 - - huggingface-hub==0.25.2 - - idna==3.10 - - imageio==2.37.0 - - imageio-ffmpeg==0.6.0 - - importlib-metadata==8.6.1 - - ipykernel==6.29.5 - - ipython==8.35.0 - - ipywidgets==8.1.6 - - isoduration==20.11.0 - - itsdangerous==2.2.0 - - jaxtyping==0.3.1 - - jedi==0.19.2 - - jinja2==3.1.6 - - joblib==1.4.2 - - json5==0.12.0 - - jsonpointer==3.0.0 - - jsonschema==4.23.0 - - jsonschema-specifications==2024.10.1 - - jupyter==1.1.1 - - jupyter-client==8.6.3 - - jupyter-console==6.6.3 - - jupyter-core==5.7.2 - - jupyter-events==0.12.0 - - jupyter-lsp==2.2.5 - - jupyter-server==2.15.0 - - jupyter-server-terminals==0.5.3 - - jupyterlab==4.4.0 - - jupyterlab-pygments==0.3.0 - - jupyterlab-server==2.27.3 - - jupyterlab-widgets==3.0.14 - - kiwisolver==1.4.8 - - lazy-loader==0.4 - - lightning-utilities==0.14.3 - - lxml==5.3.2 - - manifold3d==3.0.1 - - mapbox-earcut==1.0.3 - - markdown==3.8 - - markdown-it-py==3.0.0 - - markupsafe==3.0.2 - - matplotlib==3.10.1 - - matplotlib-inline==0.1.7 - - mdurl==0.1.2 - - mediapy==1.2.2 - - mistune==3.1.3 - - mpmath==1.3.0 - - msgpack==1.1.0 - - msgpack-numpy==0.4.8 - - msgspec==0.19.0 - - msvc-runtime==14.42.34433 - - multiprocess==0.70.17 - - narwhals==1.34.1 - - nbclient==0.10.2 - - nbconvert==7.16.6 - - nbformat==5.10.4 - - nerfacc==0.5.3 - - nerfstudio==1.1.5 - - nest-asyncio==1.6.0 - - networkx==3.4.2 - - ninja==1.11.1.4 - - nodeenv==1.9.1 - - notebook==7.4.0 - - notebook-shim==0.2.4 - - numpy==1.26.4 - - nuscenes-devkit==1.1.9 - - open3d==0.19.0 - - opencv-contrib-python==4.11.0.86 - - opencv-python==4.11.0.86 - - opencv-python-headless==4.10.0.84 - - overrides==7.7.0 - - packaging==24.2 - - pandas==2.2.3 - - pandocfilters==1.5.1 - - parso==0.8.4 - - pathos==0.3.3 - - pillow==11.1.0 - - pip==25.0.1 - - platformdirs==4.3.7 - - plotly==6.0.1 - - plyfile==1.1 - - pox==0.3.5 - - ppft==1.7.6.9 - - prometheus-client==0.21.1 - - prompt-toolkit==3.0.50 - - protobuf==3.20.3 - - psutil==7.0.0 - - pure-eval==0.2.3 - - pycocotools==2.0.8 - - pycollada==0.9 - - pycparser==2.22 - - pydantic==2.11.3 - - pydantic-core==2.33.1 - - pygments==2.19.1 - - pymeshlab==2023.12.post1 - - pyngrok==7.2.3 - - pyparsing==3.2.3 - - pyquaternion==0.9.9 - - pysocks==1.7.1 - - python-box==6.1.0 - - python-dateutil==2.9.0.post0 - - python-engineio==4.11.2 - - python-json-logger==3.3.0 - - python-socketio==5.12.1 - - pytorch-msssim==1.0.0 - - pytz==2025.2 - - pywin32==310 - - pywinpty==2.0.15 - - pyyaml==6.0.2 - - pyzmq==26.4.0 - - rawpy==0.24.0 - - referencing==0.36.2 - - regex==2024.11.6 - - requests==2.32.3 - - requests-toolbelt==1.0.0 - - retrying==1.3.4 - - rfc3339-validator==0.1.4 - - rfc3986-validator==0.1.1 - - rich==14.0.0 - - rpds-py==0.24.0 - - rtree==1.4.0 - - scikit-image==0.25.2 - - scikit-learn==1.6.1 - - scipy==1.15.2 - - semantic-version==2.10.0 - - send2trash==1.8.3 - - sentencepiece==0.1.99 - - sentry-sdk==2.25.1 - - setproctitle==1.3.5 - - setuptools==78.1.0 - - shapely==2.1.0 - - shtab==1.7.1 - - simple-websocket==1.1.0 - - simplejson==3.20.1 - - six==1.17.0 - - smmap==5.0.2 - - sniffio==1.3.1 - - soupsieve==2.6 - - splatfacto-w==0.1.5 - - splines==0.3.0 - - stack-data==0.6.3 - - svg-path==6.3 - - sympy==1.13.3 - - tensorboard==2.19.0 - - tensorboard-data-server==0.7.2 - - tensorboardx==2.6.2.2 - - tensorly==0.9.0 - - termcolor==3.0.1 - - terminado==0.18.1 - - threadpoolctl==3.6.0 - - tifffile==2025.3.30 - - timm==0.6.7 - - tinycss2==1.4.0 - - tinycudann==1.7 - - tokenizers==0.13.3 - - tomli==2.2.1 - - torch==2.1.2+cu118 - - torch-fidelity==0.3.0 - - torch-scatter==2.1.2 - - torchmetrics==1.7.1 - - torchvision==0.16.2+cu118 - - tornado==6.4.2 - - tqdm==4.67.1 - - traitlets==5.14.3 - - transformers==4.29.2 - - trimesh==4.6.6 - - typeguard==4.4.2 - - types-python-dateutil==2.9.0.20241206 - - typing-extensions==4.13.2 - - typing-inspection==0.4.0 - - tyro==0.8.12 - - tzdata==2025.2 - - uri-template==1.3.0 - - urllib3==2.4.0 - - vhacdx==0.0.8.post2 - - viser==0.2.7 - - wadler-lindig==0.1.4 - - wandb==0.19.9 - - wcwidth==0.2.13 - - webcolors==24.11.1 - - webencodings==0.5.1 - - websocket-client==1.8.0 - - websockets==15.0.1 - - werkzeug==3.0.6 - - widgetsnbextension==4.0.14 - - wrapt==1.17.2 - - wsproto==1.2.0 - - wurlitzer==3.1.1 - - xatlas==0.0.10 - - xxhash==3.5.0 - - yourdfpy==0.0.57 - - zipnerf==0.1.0 - - zipp==3.21.0 -prefix: C:\Users\crist\anaconda3\envs\nerfstudio_test diff --git a/ns_installer/__init__.py b/ns_installer/__init__.py new file mode 100644 index 0000000000..96c5c0decc --- /dev/null +++ b/ns_installer/__init__.py @@ -0,0 +1,6 @@ +from __future__ import annotations + +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +DEFAULT_LOCK_DIR = ROOT / "deps-lock" \ No newline at end of file diff --git a/ns_installer/bootstrap.py b/ns_installer/bootstrap.py new file mode 100644 index 0000000000..baeae0d02f --- /dev/null +++ b/ns_installer/bootstrap.py @@ -0,0 +1,898 @@ +from __future__ import annotations + +import os +import platform +import re +import shutil +import subprocess +import sys +import tempfile +from pathlib import Path +from typing import Optional + +from ns_installer.locks import ( + load_installer_selection, + msvc_log_filename, + msvc_selected_filename, + write_text, +) + + +def run( + cmd: list[str], + *, + check: bool = True, + capture: bool = True, + env: Optional[dict[str, str]] = None, + cwd: Optional[Path | str] = None, +) -> subprocess.CompletedProcess[str]: + return subprocess.run( + cmd, + check=check, + capture_output=capture, + text=True, + encoding="utf-8", + errors="replace", + env=env, + cwd=str(cwd) if cwd is not None else None, + ) + + +def print_run( + cmd: list[str], + *, + env: Optional[dict[str, str]] = None, + cwd: Optional[Path | str] = None, +) -> None: + print(f"[RUN] {' '.join(str(x) for x in cmd)}") + subprocess.run(cmd, check=True, env=env, cwd=str(cwd) if cwd is not None else None) + + +def which(name: str) -> Optional[str]: + return shutil.which(name) + + +def _looks_like_windows_path(value: str) -> bool: + v = (value or "").strip() + return bool(re.match(r"^[A-Za-z]:\\", v) or re.match(r"^\\\\", v)) + + +def _strip_wrapping_quotes(value: str) -> str: + v = (value or "").strip() + while len(v) >= 2 and ((v[0] == '"' and v[-1] == '"') or (v[0] == "'" and v[-1] == "'")): + v = v[1:-1].strip() + return v + + +def sanitize_windows_path(value: str) -> str: + v = (value or "").strip() + if not v: + return "" + v = v.replace("/", "\\") + v = v.replace('\\"', '"').replace("\\'", "'") + v = _strip_wrapping_quotes(v) + m = re.match(r'^[A-Za-z]:(?:\\?["\']+)([A-Za-z]:\\.*)$', v) + if m: + v = m.group(1).strip() + if len(v) >= 2 and v[0] == '"' and _looks_like_windows_path(v[1:]): + v = v[1:] + if len(v) >= 2 and v[-1] == '"' and _looks_like_windows_path(v[:-1]): + v = v[:-1] + v = v.strip().strip('"').strip("'").strip() + if _looks_like_windows_path(v): + drive_m = re.match(r'^([A-Za-z]:\\)(.*)$', v) + unc_m = re.match(r'^(\\\\[^\\]+\\[^\\]+\\?)(.*)$', v) + if drive_m: + prefix, rest = drive_m.groups() + rest = re.sub(r'\\+', r'\\', rest) + v = prefix + rest + elif unc_m: + prefix, rest = unc_m.groups() + rest = re.sub(r'\\+', r'\\', rest) + v = prefix + rest + if re.search(r'\.(exe|bat|cmd)$', v, re.I): + v = v.rstrip("\\/") + return os.path.normpath(v) if v else "" + + +def normalize_windows_path_list(value: str) -> str: + if platform.system().lower() != "windows": + return value or "" + parts: list[str] = [] + seen: set[str] = set() + for raw in (value or "").split(os.pathsep): + item = sanitize_windows_path(raw) + if not item: + continue + key = os.path.normcase(os.path.normpath(item)) + if key in seen: + continue + seen.add(key) + parts.append(os.path.normpath(item)) + return os.pathsep.join(parts) + + +def _norm_win_path(value: str) -> str: + clean = sanitize_windows_path(value) + return os.path.normpath(clean) if clean else "" + + +def _norm_win_list(values: list[str]) -> list[str]: + out: list[str] = [] + seen: set[str] = set() + for value in values: + nv = _norm_win_path(value) + if not nv: + continue + key = nv.lower() + if key in seen: + continue + seen.add(key) + out.append(nv) + return out + + +def _split_path_list(value: str | None) -> list[str]: + if not value: + return [] + return [x for x in value.split(os.pathsep) if x] + + +def _dedupe_keep_order(items: list[str]) -> list[str]: + out: list[str] = [] + seen: set[str] = set() + for item in items: + key = item.lower() + if key in seen: + continue + seen.add(key) + out.append(item) + return out + + +def _is_cuda_path_entry(path_entry: str) -> bool: + p = path_entry.replace("/", "\\").lower() + return bool( + re.search(r"\\nvidia gpu computing toolkit\\cuda\\v[\d\.]+\\bin$", p) + or re.search(r"\\nvidia gpu computing toolkit\\cuda\\v[\d\.]+\\libnvvp$", p) + or re.search(r"\\cuda\\v[\d\.]+\\bin$", p) + or re.search(r"\\cuda\\v[\d\.]+\\libnvvp$", p) + ) + + +def _remove_other_cuda_from_path(path_value: str, selected_cuda_root: str) -> str: + selected_root = _norm_win_path(selected_cuda_root).lower().replace("/", "\\") + kept: list[str] = [] + + for raw in _split_path_list(path_value): + norm = _norm_win_path(raw) + low = norm.lower().replace("/", "\\") + if _is_cuda_path_entry(norm): + if low.startswith(selected_root + "\\"): + kept.append(norm) + continue + kept.append(norm) + + return os.pathsep.join(_dedupe_keep_order(kept)) + + +def _clear_rocm_like_env(env: dict[str, str]) -> None: + for key in [ + "ROCM_HOME", + "ROCM_PATH", + "HIP_HOME", + "HIP_PATH", + "HIP_ROOT_DIR", + "HSA_PATH", + "MIOPEN_PATH", + "HIP_PLATFORM", + "HIP_COMPILER", + "HCC_AMDGPU_TARGET", + "PYTORCH_ROCM_ARCH", + "HCC_HOME", + "HIP_PATH_57", + "HIP_DEVICE_LIB_PATH", + ]: + env.pop(key, None) + + +def _detect_user_requested_cuda_from_env(env: dict[str, str]) -> str: + for key in ("CUDAToolkit_ROOT", "CUDA_HOME", "CUDA_PATH"): + value = _norm_win_path(env.get(key, "")) + if value and Path(value).exists(): + return value + return "" + + +def short_toolset_version(version: str) -> str: + version = (version or "").strip() + if not version: + return "" + parts = version.split(".") + return f"{parts[0]}.{parts[1]}" if len(parts) >= 2 else version + + +def normalize_selected_toolset(selected: dict | None) -> dict | None: + if not selected: + return None + out = dict(selected) + full = (out.get("toolset_full") or out.get("toolset") or "").strip() + out["toolset_full"] = full + out["toolset_short"] = short_toolset_version(full) + out["toolset"] = full + return out + + +def vswhere_path() -> Optional[str]: + candidates = [ + os.path.join(os.environ.get("ProgramFiles(x86)", ""), "Microsoft Visual Studio", "Installer", "vswhere.exe"), + os.path.join(os.environ.get("ProgramFiles", ""), "Microsoft Visual Studio", "Installer", "vswhere.exe"), + ] + for candidate in candidates: + if candidate and os.path.exists(candidate): + return candidate + return None + + +def list_msvc_toolsets() -> list[dict]: + if platform.system().lower() != "windows": + return [] + + out: list[dict] = [] + seen: set[tuple[str, str]] = set() + installs: list[Path] = [] + + vswhere = vswhere_path() + if vswhere: + cp = run( + [ + vswhere, + "-products", + "*", + "-requires", + "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", + "-property", + "installationPath", + ], + check=False, + ) + for line in cp.stdout.splitlines(): + line = line.strip() + if line: + installs.append(Path(line)) + + fallback_roots = [ + Path(os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")) / "Microsoft Visual Studio", + Path(os.environ.get("ProgramFiles", r"C:\Program Files")) / "Microsoft Visual Studio", + ] + for root in fallback_roots: + if not root.exists(): + continue + for year_dir in root.iterdir(): + if not year_dir.is_dir(): + continue + for edition_dir in year_dir.iterdir(): + if edition_dir.is_dir(): + installs.append(edition_dir) + + dedup_installs: list[Path] = [] + seen_install = set() + for inst in installs: + key = os.path.normcase(str(inst)) + if key in seen_install: + continue + seen_install.add(key) + dedup_installs.append(inst) + + for root in dedup_installs: + msvc_root = root / "VC" / "Tools" / "MSVC" + if not msvc_root.exists(): + continue + for d in sorted(msvc_root.iterdir()): + if not d.is_dir(): + continue + vcvarsall = root / "VC" / "Auxiliary" / "Build" / "vcvarsall.bat" + cl = d / "bin" / "Hostx64" / "x64" / "cl.exe" + if not (vcvarsall.exists() and cl.exists()): + continue + key = (str(root), d.name) + if key in seen: + continue + seen.add(key) + normalized = normalize_selected_toolset( + { + "installation": _norm_win_path(str(root)), + "toolset": d.name, + "vcvarsall": _norm_win_path(str(vcvarsall)), + "cl": _norm_win_path(str(cl)), + } + ) + if normalized: + out.append(normalized) + + out.sort(key=lambda x: x["toolset_full"], reverse=True) + return out + + +def write_msvc_log(lock_dir: Path) -> list[dict]: + toolsets = list_msvc_toolsets() + lines: list[str] = [] + if not toolsets: + lines.append("No MSVC toolsets detected.") + else: + lines.append("Detected MSVC toolsets:") + for t in toolsets: + lines.append( + f"{t['toolset_full']} | short={t['toolset_short']} | " + f"install={t['installation']} | cl={t['cl']} | vcvarsall={t['vcvarsall']}" + ) + write_text(msvc_log_filename(lock_dir), "\n".join(lines) + "\n") + return toolsets + + +def choose_msvc_toolset(lock_dir: Path, requested: str) -> Optional[dict]: + toolsets = write_msvc_log(lock_dir) + requested = (requested or "").strip().lower() + + if not toolsets or requested in {"", "system"}: + return None + + if requested == "auto": + for t in toolsets: + if t["toolset_short"] == "14.38" or t["toolset_full"].startswith("14.38"): + return t + return toolsets[0] + + if requested == "14": + for t in toolsets: + if t["toolset_full"].startswith("14."): + return t + return None + + for t in toolsets: + if t["toolset_short"] == requested or t["toolset_full"].startswith(requested): + return t + + return None + + +def detect_cuda_root(*, cuda_mode: str = "vanilla") -> str: + default_cuda_118 = ( + Path(os.environ.get("ProgramFiles", r"C:\Program Files")) + / "NVIDIA GPU Computing Toolkit" + / "CUDA" + / "v11.8" + ) + + if cuda_mode != "experimental-env" and default_cuda_118.exists(): + return str(default_cuda_118) + + candidates = [os.environ.get("CUDA_PATH", ""), os.environ.get("CUDA_HOME", ""), os.environ.get("CUDAToolkit_ROOT", "")] + for cand in candidates: + cand = _norm_win_path(cand) + if cand and Path(cand).exists(): + return cand + + nvcc = shutil.which("nvcc.exe") or shutil.which("nvcc") + if nvcc: + try: + return str(Path(nvcc).resolve().parent.parent) + except Exception: + pass + + return str(default_cuda_118) if default_cuda_118.exists() else "" + + +def detect_git_dirs() -> list[str]: + candidates: list[str] = [] + seen: set[str] = set() + + git_exe = shutil.which("git.exe") or shutil.which("git") + if git_exe: + gp = os.path.normpath(str(Path(git_exe).resolve().parent)) + key = os.path.normcase(gp) + if key not in seen: + seen.add(key) + candidates.append(gp) + + program_files = os.environ.get("ProgramFiles", r"C:\Program Files") + for p in (Path(program_files) / "Git" / "cmd", Path(program_files) / "Git" / "bin"): + if p.exists(): + gp = os.path.normpath(str(p)) + key = os.path.normcase(gp) + if key not in seen: + seen.add(key) + candidates.append(gp) + + return candidates + + +def get_runtime_path_entries() -> list[str]: + entries: list[str] = [] + conda_prefix = os.environ.get("CONDA_PREFIX", "") + if conda_prefix: + prefix = Path(conda_prefix) + for p in ( + prefix / "Scripts", + prefix, + prefix / "Library" / "bin", + prefix / "Library" / "usr" / "bin", + prefix / "bin", + ): + entries.append(str(p)) + entries.append(str(Path(sys.executable).resolve().parent)) + entries.extend(detect_git_dirs()) + return entries + + +def parse_set_output_to_env(text: str) -> dict[str, str]: + parsed_env: dict[str, str] = {} + path_list_keys = {"PATH", "INCLUDE", "LIB", "LIBPATH"} + path_scalar_keys = { + "CC", + "CXX", + "CUDAHOSTCXX", + "CLCACHE_CL", + "CMAKE_CUDA_HOST_COMPILER", + "VCToolsInstallDir", + "VCINSTALLDIR", + "VSINSTALLDIR", + "WindowsSdkDir", + "WindowsSDKVersion", + "UniversalCRTSdkDir", + "UCRTVersion", + "CUDA_PATH", + "CUDA_HOME", + "CUDAToolkit_ROOT", + } + path_scalar_keys_upper = {x.upper() for x in path_scalar_keys} + + for line in (text or "").splitlines(): + if "=" not in line: + continue + k, v = line.split("=", 1) + k = k.strip() + if not k: + continue + ku = k.upper() + if ku in path_list_keys: + parsed_env[k] = normalize_windows_path_list(v) + elif ku in path_scalar_keys_upper: + parsed_env[k] = _norm_win_path(v) + else: + parsed_env[k] = v.strip().replace('\\"', '"').replace('""', '"') + return parsed_env + + +def _capture_vcvars_env(vcvarsall: str, short_ver: str, full_ver: str) -> dict[str, str]: + cmd_lines = [ + "@echo off", + "setlocal EnableExtensions", + f'call "{vcvarsall}" x64 -vcvars_ver={short_ver}', + f'if errorlevel 1 call "{vcvarsall}" x64 -vcvars_ver={full_ver}', + f'if errorlevel 1 call "{vcvarsall}" x64', + "if errorlevel 1 exit /b %errorlevel%", + "set", + ] + script = "\r\n".join(cmd_lines) + "\r\n" + + with tempfile.NamedTemporaryFile("w", suffix=".cmd", delete=False, encoding="utf-8", newline="\r\n") as f: + f.write(script) + temp_cmd = f.name + + try: + cp = subprocess.run( + ["cmd", "/d", "/s", "/c", temp_cmd], + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + check=True, + ) + return parse_set_output_to_env(cp.stdout) + finally: + try: + os.unlink(temp_cmd) + except OSError: + pass + + +def apply_cuda_env_policy( + env: dict[str, str], + selected_cuda_root: str, + *, + cuda_mode: str = "vanilla", +) -> dict[str, str]: + env = dict(env) + _clear_rocm_like_env(env) + + bootstrap_cuda = _norm_win_path(selected_cuda_root) + user_cuda = _detect_user_requested_cuda_from_env(env) + + if cuda_mode == "experimental-env" and user_cuda: + active_cuda = user_cuda + else: + active_cuda = bootstrap_cuda + + if not active_cuda: + return env + + cuda_bin = _norm_win_path(str(Path(active_cuda) / "bin")) + cuda_libnvvp = _norm_win_path(str(Path(active_cuda) / "libnvvp")) + + env["CUDA_PATH"] = active_cuda + env["CUDA_HOME"] = active_cuda + env["CUDAToolkit_ROOT"] = active_cuda + env["CUDA_BIN_PATH"] = cuda_bin + + cleaned_path = _remove_other_cuda_from_path(env.get("PATH", ""), active_cuda) + new_path_entries = [cuda_bin, cuda_libnvvp] + _split_path_list(cleaned_path) + env["PATH"] = os.pathsep.join(_dedupe_keep_order([x for x in new_path_entries if x])) + + return env + + +def build_bootstrap_context(lock_dir: Path, requested: str, *, cuda_mode: str = "vanilla") -> dict: + installer = load_installer_selection(lock_dir) + effective = str( + installer.get("preferred_msvc") or requested or os.environ.get("PREFERRED_MSVC") or "" + ).strip() + + selected = None + materialized_env: dict[str, str] = {} + cuda_root = "" + git_dirs: list[str] = [] + runtime_entries: list[str] = [] + + if platform.system().lower() == "windows": + selected = normalize_selected_toolset(choose_msvc_toolset(lock_dir, effective)) + if selected: + selected = { + **selected, + "installation": _norm_win_path(selected.get("installation", "")), + "vcvarsall": _norm_win_path(selected.get("vcvarsall", "")), + "cl": _norm_win_path(selected.get("cl", "")), + } + try: + materialized_env = _capture_vcvars_env( + selected["vcvarsall"], + selected["toolset_short"], + selected["toolset_full"], + ) + except Exception: + materialized_env = {} + + cuda_root = _norm_win_path(detect_cuda_root(cuda_mode=cuda_mode)) + git_dirs = _norm_win_list(detect_git_dirs()) + runtime_entries = _norm_win_list(get_runtime_path_entries()) + + ctx = { + "requested": effective, + "selected": selected, + "cuda_root": cuda_root, + "git_dirs": git_dirs, + "runtime_path_entries": runtime_entries, + "materialized_env": materialized_env, + "cuda_mode": cuda_mode, + } + + lines = [ + f"requested={effective or 'system'}", + f"cuda_mode={cuda_mode}", + f"cuda_root={cuda_root}", + f"git_dirs={';'.join(git_dirs)}", + f"runtime_path_entries={';'.join(runtime_entries)}", + f"include={materialized_env.get('INCLUDE', '')}", + f"lib={materialized_env.get('LIB', '')}", + f"libpath={materialized_env.get('LIBPATH', '')}", + f"winsdk={materialized_env.get('WindowsSdkDir', '')}", + f"ucrt={materialized_env.get('UniversalCRTSdkDir', '')}", + ] + if selected: + lines.extend( + [ + f"selected_toolset={selected['toolset_full']}", + f"selected_short={selected['toolset_short']}", + f"selected_install={selected['installation']}", + f"selected_cl={selected['cl']}", + f"selected_vcvarsall={selected['vcvarsall']}", + "mode=subprocess-shell-bootstrap", + ] + ) + else: + lines.append("mode=system/no-forced-toolset") + + write_text(msvc_selected_filename(lock_dir), "\n".join(lines) + "\n") + return ctx + + +def build_bootstrap_env( + lock_dir: Path, + requested: str, + extra_env: Optional[dict[str, str]] = None, + *, + cuda_mode: str = "vanilla", +) -> dict[str, str]: + ctx = build_bootstrap_context(lock_dir, requested, cuda_mode=cuda_mode) + env = os.environ.copy() + materialized = dict(ctx.get("materialized_env") or {}) + selected = ctx.get("selected") + runtime_entries = list(ctx.get("runtime_path_entries", [])) + cuda_root = _norm_win_path(ctx.get("cuda_root", "")) + + for key, value in materialized.items(): + if key.upper() in {"PATH", "INCLUDE", "LIB", "LIBPATH"}: + env[key] = normalize_windows_path_list(value) + else: + env[key] = value + + if selected: + cl = _norm_win_path(selected.get("cl", "")) + full_ver = str(selected.get("toolset_full", "")).strip() + env["NS_SELECTED_MSVC_TOOLSET"] = full_ver + env["NS_SELECTED_MSVC_CL"] = cl + env["CC"] = cl + env["CXX"] = cl + env["CUDAHOSTCXX"] = cl + env["CLCACHE_CL"] = cl + env["CMAKE_CUDA_HOST_COMPILER"] = cl + env["DISTUTILS_USE_SDK"] = "1" + env["MSSdk"] = "1" + env["CMAKE_GENERATOR"] = "Visual Studio 17 2022" + if full_ver: + env["CMAKE_GENERATOR_TOOLSET"] = f"v143,version={full_ver}" + + merged_runtime = normalize_windows_path_list(os.pathsep.join(runtime_entries)) + if merged_runtime: + current_path = env.get("PATH", "") + env["PATH"] = f"{merged_runtime}{os.pathsep}{current_path}" if current_path else merged_runtime + + env = apply_cuda_env_policy(env, cuda_root, cuda_mode=cuda_mode) + + if extra_env: + for k, v in extra_env.items(): + if v is None: + continue + env[k] = str(v) + + return env + + +def write_bootstrap_env_snapshot(lock_dir: Path, env: dict[str, str]) -> Path: + snapshot_path = lock_dir / "bootstrap-env.txt" + lines = [] + for key in [ + "NS_SELECTED_MSVC_TOOLSET", + "NS_SELECTED_MSVC_CL", + "CC", + "CXX", + "CUDAHOSTCXX", + "CMAKE_CUDA_HOST_COMPILER", + "CMAKE_GENERATOR", + "CMAKE_GENERATOR_TOOLSET", + "CUDA_PATH", + "CUDA_HOME", + "CUDAToolkit_ROOT", + "WindowsSdkDir", + "WindowsSDKVersion", + "UniversalCRTSdkDir", + "UCRTVersion", + "VCToolsInstallDir", + "VCINSTALLDIR", + "VSINSTALLDIR", + "INCLUDE", + "LIB", + "LIBPATH", + "PATH", + ]: + lines.append(f"{key}={env.get(key, '')}") + write_text(snapshot_path, "\n".join(lines) + "\n") + return snapshot_path + + +def find_header_in_include(include_value: str, header_name: str) -> str: + header_name = (header_name or "").strip() + if not header_name: + return "" + for raw in normalize_windows_path_list(include_value).split(os.pathsep): + root = _norm_win_path(raw) + if not root: + continue + p = Path(root) / header_name + if p.exists(): + return str(p) + return "" + + +def validate_msvc_from_shell(lock_dir: Path, ctx: dict) -> tuple[bool, list[str]]: + if platform.system().lower() != "windows": + return True, [] + + selected = ctx.get("selected") + if not selected: + return True, [] + + errors: list[str] = [] + vcvarsall = _norm_win_path(selected.get("vcvarsall", "")) + cl = _norm_win_path(selected.get("cl", "")) + + if not vcvarsall or not Path(vcvarsall).exists(): + errors.append(f"vcvarsall missing: {vcvarsall}") + if not cl or not Path(cl).exists(): + errors.append(f"cl.exe missing: {cl}") + + env = ctx.get("materialized_env") or {} + include_value = env.get("INCLUDE", "") + if not include_value: + errors.append("INCLUDE is empty after vcvars materialization") + else: + if not find_header_in_include(include_value, "corecrt.h"): + errors.append("corecrt.h not found inside INCLUDE") + if not find_header_in_include(include_value, "Windows.h"): + errors.append("Windows.h not found inside INCLUDE") + + return len(errors) == 0, errors + + +def _cmdline_from_args(args: list[str]) -> str: + return subprocess.list2cmdline([str(x) for x in args]) + + +def _make_bootstrap_batch( + lock_dir: Path, + command: list[str], + msvc_mode: str, + *, + cwd: Optional[Path | str] = None, + extra_env: Optional[dict[str, str]] = None, + cuda_mode: str = "vanilla", +) -> str: + ctx = build_bootstrap_context(lock_dir, msvc_mode, cuda_mode=cuda_mode) + ok, errors = validate_msvc_from_shell(lock_dir, ctx) + if not ok: + raise RuntimeError("MSVC bootstrap metadata invalid: " + "; ".join(errors)) + + selected = ctx.get("selected") + final_env = build_bootstrap_env( + lock_dir, + msvc_mode, + extra_env=extra_env, + cuda_mode=cuda_mode, + ) + + lines: list[str] = ["@echo off", "setlocal EnableExtensions"] + + if cwd is not None: + lines.append(f'cd /d "{Path(cwd).resolve()}"') + lines.append("if errorlevel 1 exit /b %errorlevel%") + + if platform.system().lower() == "windows" and selected: + vcvarsall = _norm_win_path(selected["vcvarsall"]) + short_ver = selected["toolset_short"] + full_ver = selected["toolset_full"] + lines.extend( + [ + f'call "{vcvarsall}" x64 -vcvars_ver={short_ver}', + f'if errorlevel 1 call "{vcvarsall}" x64 -vcvars_ver={full_ver}', + f'if errorlevel 1 call "{vcvarsall}" x64', + "if errorlevel 1 exit /b %errorlevel%", + ] + ) + + export_keys = [ + "NS_SELECTED_MSVC_TOOLSET", + "NS_SELECTED_MSVC_CL", + "CC", + "CXX", + "CUDAHOSTCXX", + "CLCACHE_CL", + "CMAKE_CUDA_HOST_COMPILER", + "CMAKE_GENERATOR", + "CMAKE_GENERATOR_TOOLSET", + "DISTUTILS_USE_SDK", + "MSSdk", + "CUDA_PATH", + "CUDA_HOME", + "CUDAToolkit_ROOT", + "CUDA_BIN_PATH", + "WindowsSdkDir", + "WindowsSDKVersion", + "UniversalCRTSdkDir", + "UCRTVersion", + "VCToolsInstallDir", + "VCINSTALLDIR", + "VSINSTALLDIR", + "INCLUDE", + "LIB", + "LIBPATH", + "PATH", + ] + + for key in export_keys: + value = final_env.get(key, "") + if value: + lines.append(f'set "{key}={value}"') + + for key in ( + "ROCM_HOME", + "ROCM_PATH", + "HIP_HOME", + "HIP_PATH", + "HIP_ROOT_DIR", + "HSA_PATH", + "MIOPEN_PATH", + "HIP_PLATFORM", + "HIP_COMPILER", + "HCC_AMDGPU_TARGET", + "PYTORCH_ROCM_ARCH", + "HCC_HOME", + "HIP_PATH_57", + "HIP_DEVICE_LIB_PATH", + ): + lines.append(f'set "{key}="') + + lines.append(_cmdline_from_args(command)) + lines.append("exit /b %errorlevel%") + return "\n".join(lines) + "\n" + + +def run_bootstrapped( + lock_dir: Path, + command: list[str], + msvc_mode: str, + *, + check: bool = True, + cwd: Optional[Path | str] = None, + extra_env: Optional[dict[str, str]] = None, + cuda_mode: str = "vanilla", +) -> subprocess.CompletedProcess: + if platform.system().lower() != "windows": + env = os.environ.copy() + if extra_env: + env.update({k: str(v) for k, v in extra_env.items() if v is not None}) + return subprocess.run( + command, + check=check, + env=env, + cwd=str(cwd) if cwd is not None else None, + ) + + script = _make_bootstrap_batch( + lock_dir, + command, + msvc_mode, + cwd=cwd, + extra_env=extra_env, + cuda_mode=cuda_mode, + ) + with tempfile.NamedTemporaryFile("w", suffix=".cmd", delete=False, encoding="utf-8", newline="\r\n") as f: + f.write(script) + temp_cmd = f.name + try: + return subprocess.run(["cmd", "/d", "/s", "/c", temp_cmd], check=check) + finally: + try: + os.unlink(temp_cmd) + except OSError: + pass + + +def print_run_bootstrapped( + lock_dir: Path, + command: list[str], + msvc_mode: str, + *, + cwd: Optional[Path | str] = None, + extra_env: Optional[dict[str, str]] = None, + cuda_mode: str = "vanilla", +) -> None: + print(f"[RUN] {' '.join(str(x) for x in command)}") + run_bootstrapped( + lock_dir, + command, + msvc_mode, + check=True, + cwd=cwd, + extra_env=extra_env, + cuda_mode=cuda_mode, + ) \ No newline at end of file diff --git a/ns_installer/build.py b/ns_installer/build.py new file mode 100644 index 0000000000..382afdb41a --- /dev/null +++ b/ns_installer/build.py @@ -0,0 +1,603 @@ +from __future__ import annotations + +import os +import subprocess +import sys +from pathlib import Path + +from ns_installer import DEFAULT_LOCK_DIR +from ns_installer.bootstrap import print_run_bootstrapped, run, which +from ns_installer.locks import ( + DEFAULT_NUMPY, + DEFAULT_TORCH, + PYG_INDEX_TEMPLATE, + TORCH_INDEX, + load_build_plan, + normalize_lines, + normalize_pkg_line, + parse_name, + pip_lock_filename, + read_text, + write_text, +) +from ns_installer.protected import ( + NERFSTUDIO_CORE_OVERRIDES, + PROTECTED_GIT_PACKAGES, + TCNN_GIT, +) + + +PIP_VERBOSE_ARGS = ["-v"] +BUILD_TOOL_PKGS = ["pip", "setuptools", "wheel", "Cython", "pkgconfig", "pybind11", "ninja", "cmake"] + + +def normalized_current_pip_lines() -> list[str]: + try: + cp = run([sys.executable, "-m", "pip", "freeze", "--all"]) + except subprocess.CalledProcessError: + cp = run([sys.executable, "-m", "pip", "freeze"]) + return [normalize_pkg_line(x) for x in normalize_lines(cp.stdout, kind="pip")] + + +def installed_pip_map() -> dict[str, str]: + return {parse_name(x): normalize_pkg_line(x) for x in normalized_current_pip_lines()} + + +def installed_direct_url_map() -> dict[str, str]: + cp = subprocess.run( + [sys.executable, "-m", "pip", "freeze", "--all"], + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + check=False, + ) + out: dict[str, str] = {} + for raw in normalize_lines(cp.stdout, kind="pip"): + line = normalize_pkg_line(raw) + if " @ " not in line: + continue + out[parse_name(line)] = line + return out + + +def get_installed_version(pkg_name: str) -> str: + try: + import importlib.metadata as importlib_metadata + except Exception: + import importlib_metadata # type: ignore + + for candidate in {pkg_name, pkg_name.replace("-", "_"), pkg_name.replace("_", "-")}: + try: + return importlib_metadata.version(candidate) + except Exception: + pass + return "" + + +def git_requirement_matches(installed_line: str, expected_git: str) -> bool: + a = (installed_line or "").strip().lower() + b = (expected_git or "").strip().lower() + return bool(a and b and b in a) + + +def spec_is_exact_pin(spec: str) -> bool: + return "==" in spec and " @ " not in spec and not spec.startswith(("-", "--")) + + +def filter_already_installed_exact_specs(lines: list[str]) -> tuple[list[str], list[str]]: + installed = installed_pip_map() + pending, skipped = [], [] + for raw in lines: + line = normalize_pkg_line(raw) + if spec_is_exact_pin(line): + name = parse_name(line) + if installed.get(name, "") == line: + skipped.append(line) + continue + pending.append(line) + return pending, skipped + + +def detect_tcnn_runtime() -> bool: + try: + cp = run([sys.executable, "-c", "import tinycudann as tcnn; print('OK')"], check=False) + return cp.returncode == 0 + except Exception: + return False + + +def tcnn_runtime_ok(expected_arch: str = "") -> bool: + try: + import torch + import tinycudann as _tcnn # noqa: F401 + return torch.cuda.is_available() + except Exception: + return False + + +def torch_pyg_tag(torch_line: str) -> str: + version = torch_line.split("==", 1)[1].strip() if "==" in torch_line else "2.1.2+cu118" + return f"torch-{version}" + + +def torch_cuda_arch_list_value(value: str) -> str: + raw = (value or "").strip() + if not raw: + return "" + parts = [x.strip() for x in raw.replace(",", ";").split(";") if x.strip()] + out = [] + for p in parts: + if "." in p: + out.append(p) + elif p.isdigit() and len(p) >= 2: + out.append(f"{p[0]}.{p[1:]}") + else: + out.append(p) + return ";".join(out) + + +def current_tcnn_arch() -> str: + return ( + os.environ.get("TCNN_CUDA_ARCHITECTURES", "") + or os.environ.get("CUDA_ARCH", "") + or os.environ.get("TORCH_CUDA_ARCH_LIST", "") + ).strip() + + +def install_packaging_base(lock_dir: Path, msvc_mode: str) -> None: + print("[INFO] Installing build/runtime base tooling...") + print_run_bootstrapped( + lock_dir, + [sys.executable, "-m", "pip", "install", *PIP_VERBOSE_ARGS, "--upgrade", "--force-reinstall", *BUILD_TOOL_PKGS], + msvc_mode, + ) + + +def ensure_build_tooling_for_cpp(lock_dir: Path, msvc_mode: str) -> None: + print("[INFO] Repairing Python build tooling required by native extensions...") + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "pip", + "setuptools==75.1.0", + "wheel==0.44.0", + "Cython", + "pkgconfig", + "pybind11", + "ninja", + "cmake", + ], + msvc_mode, + ) + + +def ensure_numpy_stable(lock_dir: Path, msvc_mode: str, numpy_spec: str, state: dict, *, reason: str) -> None: + desired = numpy_spec.split("==", 1)[1] if "==" in numpy_spec else "" + current = get_installed_version("numpy") + if state.get("numpy_version") == desired and current == desired: + print(f"[INFO] NumPy already stable at {desired}; skipping reinstall ({reason}).") + return + print(f"[INFO] Enforcing stable NumPy policy: {numpy_spec} ({reason})") + print_run_bootstrapped( + lock_dir, + [sys.executable, "-m", "pip", "install", *PIP_VERBOSE_ARGS, "--upgrade", "--force-reinstall", numpy_spec], + msvc_mode, + ) + state["numpy_version"] = desired or get_installed_version("numpy") + + +def install_torch_preinstall(lock_dir: Path, msvc_mode: str, torch_lines: list[str], numpy_spec: str, state: dict) -> None: + torch_lines = torch_lines or DEFAULT_TORCH[:] + pending, skipped = filter_already_installed_exact_specs(torch_lines) + if skipped: + print(f"[INFO] Skipping already-installed torch package(s): {', '.join(skipped)}") + if not pending: + state["numpy_version"] = numpy_spec.split("==", 1)[1] if "==" in numpy_spec else state.get("numpy_version", "") + return + + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + numpy_spec, + *pending, + "--index-url", + TORCH_INDEX, + ], + msvc_mode, + ) + state["numpy_version"] = numpy_spec.split("==", 1)[1] if "==" in numpy_spec else state.get("numpy_version", "") + + +def install_pyg_wheels(lock_dir: Path, msvc_mode: str, torch_lines: list[str], pyg_lines: list[str]) -> None: + if not pyg_lines: + return + + torch_line = next((x for x in torch_lines if x.lower().startswith("torch==")), DEFAULT_TORCH[0]) + index_url = PYG_INDEX_TEMPLATE.format(torch_tag=torch_pyg_tag(torch_line)) + pending, skipped = filter_already_installed_exact_specs(pyg_lines) + + if skipped: + print(f"[INFO] Skipping already-installed PyG wheel(s): {', '.join(skipped)}") + + for line in pending: + print_run_bootstrapped( + lock_dir, + [sys.executable, "-m", "pip", "install", *PIP_VERBOSE_ARGS, line, "-f", index_url], + msvc_mode, + ) + + +def install_requirements_file(lock_dir: Path, msvc_mode: str, lines: list[str], tmp_path: Path) -> None: + if not lines: + return + + pending, skipped = filter_already_installed_exact_specs([normalize_pkg_line(x) for x in lines]) + if skipped: + print( + f"[INFO] Skipping already-installed exact requirement(s): {', '.join(skipped[:20])}" + + (" ..." if len(skipped) > 20 else "") + ) + if not pending: + return + + write_text(tmp_path, "\n".join(pending) + "\n") + try: + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "--no-deps", + "--no-build-isolation", + "-r", + str(tmp_path), + ], + msvc_mode, + ) + finally: + try: + tmp_path.unlink() + except OSError: + pass + + +def install_tcnn(lock_dir: Path, msvc_mode: str, tcnn_line: str, tcnn_arch: str) -> None: + if tcnn_runtime_ok(tcnn_arch): + return + + ensure_build_tooling_for_cpp(lock_dir, msvc_mode) + plan = load_build_plan(lock_dir) + selected_arch = (tcnn_arch or str((plan.get("tinycudann") or {}).get("cuda_arch", ""))).strip() + selected_req = (tcnn_line or str((plan.get("tinycudann") or {}).get("requirement", ""))).strip() or TCNN_GIT + + extra_env = { + "FORCE_CUDA": "1", + "TORCH_CUDA_ARCH_LIST": torch_cuda_arch_list_value(selected_arch), + "MAX_JOBS": "1", + "CMAKE_BUILD_PARALLEL_LEVEL": "1", + "DISTUTILS_USE_SDK": "1", + "MSSdk": "1", + "ROCM_HOME": "", + "ROCM_PATH": "", + "HIP_HOME": "", + "HIP_PATH": "", + "HCC_HOME": "", + "HIP_PATH_57": "", + "HIP_DEVICE_LIB_PATH": "", + "PYTORCH_ROCM_ARCH": "", + } + if selected_arch: + extra_env["TCNN_CUDA_ARCHITECTURES"] = selected_arch + + try: + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "--no-build-isolation", + "--no-cache-dir", + selected_req, + ], + msvc_mode, + extra_env=extra_env, + ) + except Exception: + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "--no-build-isolation", + "--no-cache-dir", + TCNN_GIT, + ], + msvc_mode, + extra_env=extra_env, + ) + + +def install_deferred(lock_dir: Path, msvc_mode: str, lines: list[str]) -> None: + leftovers = [x for x in lines if "tinycudann" not in x.lower() and "tiny-cuda-nn" not in x.lower()] + if leftovers: + install_requirements_file(lock_dir, msvc_mode, leftovers, lock_dir / ".tmp-deferred-install.txt") + + +def install_av(lock_dir: Path, msvc_mode: str, lines: list[str]) -> None: + if not lines: + return + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "setuptools<81", + "wheel", + "pip", + "Cython", + "pkgconfig", + "pybind11", + "numpy<2", + ], + msvc_mode, + ) + install_requirements_file(lock_dir, msvc_mode, lines, lock_dir / ".tmp-av-install.txt") + + +def choose_conda_restore_cmd(conda_exe: str, explicit_file: Path) -> list[str]: + mamba = which("mamba") or which("mamba.exe") + micromamba = which("micromamba") or which("micromamba.exe") + if mamba: + return [mamba, "install", "--yes", "--verbose", "--file", str(explicit_file)] + if micromamba: + return [micromamba, "install", "--yes", "--verbose", "--file", str(explicit_file)] + return [conda_exe, "install", "--solver=libmamba", "--yes", "--verbose", "--file", str(explicit_file)] + + +def install_remaining_from_full_lock(lock_dir: Path, msvc_mode: str) -> None: + full_lock = pip_lock_filename(lock_dir) + if not full_lock.exists(): + return + + current_names = {parse_name(x) for x in normalized_current_pip_lines()} + wanted = [] + for raw in normalize_lines(read_text(full_lock), kind="pip"): + cand = normalize_pkg_line(raw) + name = parse_name(cand) + if name in current_names or name in {"numpy", "torch", "torchvision", "torchaudio", "tinycudann", "tiny-cuda-nn"}: + continue + if " @ file:///" in cand or cand.startswith("-e ") or "cuda_backend==" in cand: + continue + wanted.append(cand) + + wanted = list(dict.fromkeys(wanted)) + if wanted: + install_requirements_file(lock_dir, msvc_mode, wanted, lock_dir / ".tmp-full-remaining-install.txt") + + +def restore_core_overrides(lock_dir: Path, msvc_mode: str) -> None: + current_direct = installed_direct_url_map() + restore_specs = [] + + for _, spec in NERFSTUDIO_CORE_OVERRIDES.items(): + install_ref = str(spec.get("install_ref", "")).strip() + pip_names = [str(x).strip().lower().replace("_", "-") for x in spec.get("pip_names", set())] + matched = False + for pip_name in pip_names: + if git_requirement_matches(current_direct.get(pip_name, ""), install_ref): + matched = True + break + if not matched and install_ref: + restore_specs.append(install_ref) + + if restore_specs: + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + "--no-build-isolation", + "--no-cache-dir", + *list(dict.fromkeys(restore_specs)), + ], + msvc_mode, + ) + + +def restore_protected_from_lock(lock_dir: Path, msvc_mode: str) -> None: + full_lock = pip_lock_filename(lock_dir) + if not full_lock.exists(): + return + + locked = {} + for raw in normalize_lines(read_text(full_lock), kind="pip"): + line = normalize_pkg_line(raw) + name = parse_name(line) + if name in {"numpy", "torch", "torchvision", "torchaudio", "tinycudann", "tiny-cuda-nn", "pycolmap"}: + locked[name] = line + + current = {parse_name(x): x for x in normalized_current_pip_lines()} + restore_specs = [] + + for name, spec in locked.items(): + if spec and current.get(name, "") != spec and " @ file:///" not in spec: + restore_specs.append(spec) + + for name, git_spec in PROTECTED_GIT_PACKAGES.items(): + if not git_requirement_matches(installed_direct_url_map().get(name, ""), git_spec): + restore_specs.append(git_spec) + + torch_specs = [x for x in restore_specs if parse_name(x) in {"torch", "torchvision", "torchaudio"}] + other_specs = [x for x in restore_specs if parse_name(x) not in {"torch", "torchvision", "torchaudio"}] + + if torch_specs: + print_run_bootstrapped( + lock_dir, + [ + sys.executable, + "-m", + "pip", + "install", + *PIP_VERBOSE_ARGS, + "--upgrade", + "--force-reinstall", + *torch_specs, + "--index-url", + TORCH_INDEX, + ], + msvc_mode, + ) + + if other_specs: + install_requirements_file(lock_dir, msvc_mode, other_specs, lock_dir / ".tmp-protected-restore.txt") + + +def print_strict_alignment_status(lock_dir: Path) -> None: + plan = load_build_plan(lock_dir) + pip_set = {parse_name(x): x for x in normalized_current_pip_lines()} + + print("[INFO] Strict alignment status:") + print(f" [TARGET NUMPY] {plan.get('numpy_stable', DEFAULT_NUMPY)}") + for name in ["numpy", "torch", "torchvision", "torchaudio", "pycolmap"]: + if name in pip_set: + print(f" [OK] {pip_set[name]}") + else: + print(f" [MISS] {name}") + print(f" [RUNTIME tinycudann] {'OK' if detect_tcnn_runtime() else 'MISSING'}") + + +def install_editable_project( + project_dir: Path, + *, + lock_dir: Path | None = None, + msvc_mode: str = "", + cuda_mode: str = "vanilla", # ✅ PATCH + no_deps: bool = True, + no_build_isolation: bool = False, +) -> None: + lock_dir = lock_dir or DEFAULT_LOCK_DIR + + cmd = [sys.executable, "-m", "pip", "install", *PIP_VERBOSE_ARGS] + + if no_deps: + cmd.append("--no-deps") + if no_build_isolation: + cmd.append("--no-build-isolation") + + cmd.extend(["-e", str(project_dir)]) + + print_run_bootstrapped( + lock_dir, + cmd, + msvc_mode, + cuda_mode=cuda_mode, # ✅ CRUCIALE + cwd=project_dir, + ) + +def build_tetra_nerf_windows( + repo_dir: Path, + *, + lock_dir: Path | None = None, + msvc_mode: str = "", + cuda_mode: str = "vanilla", # ✅ PATCH +) -> None: + lock_dir = lock_dir or DEFAULT_LOCK_DIR + + print_run_bootstrapped( + lock_dir, + [sys.executable, "setup.py", "build_ext"], + msvc_mode, + cuda_mode=cuda_mode, # ✅ CRUCIALE + cwd=repo_dir, + ) + +def build_zipnerf_cuda_windows(repo_dir: Path, *, lock_dir: Path | None = None, msvc_mode: str = "", cuda_mode: str = "vanilla") -> None: + lock_dir = lock_dir or DEFAULT_LOCK_DIR + ensure_build_tooling_for_cpp(lock_dir, msvc_mode) + + candidates = [repo_dir / "make_patch_zipnerf_cuda.bat", repo_dir / "make_zipnerf_cuda.bat"] + for script in candidates: + if script.exists(): + print_run_bootstrapped( + lock_dir, + ["cmd", "/d", "/s", "/c", str(script)], + msvc_mode, + cuda_mode=cuda_mode, + cwd=repo_dir, + ) + return + + print("[WARN] No Windows zipnerf CUDA build script found; skipped.") + + +def maybe_build_method_native( + method_name: str, + repo_dir: Path, + *, + lock_dir: Path | None = None, + msvc_mode: str = "", + cuda_mode: str = "vanilla", # ✅ PATCH +) -> None: + if method_name == "tetra-nerf": + build_tetra_nerf_windows( + repo_dir, + lock_dir=lock_dir, + msvc_mode=msvc_mode, + cuda_mode=cuda_mode, # ✅ + ) + +def repin_after_method_install( + lock_dir: Path, + msvc_mode: str, + cuda_mode: str = "vanilla", # opzionale ma coerente +) -> None: + plan = load_build_plan(lock_dir) + numpy_spec = plan.get("numpy_stable") or DEFAULT_NUMPY + state: dict = {} + + ensure_numpy_stable(lock_dir, msvc_mode, numpy_spec, state, reason="post-method") + + restore_core_overrides(lock_dir, msvc_mode) + restore_protected_from_lock(lock_dir, msvc_mode) + + ensure_numpy_stable(lock_dir, msvc_mode, numpy_spec, state, reason="post-protected-restore") \ No newline at end of file diff --git a/ns_installer/cli.py b/ns_installer/cli.py new file mode 100644 index 0000000000..3601ded5cf --- /dev/null +++ b/ns_installer/cli.py @@ -0,0 +1,309 @@ +from __future__ import annotations +import argparse +import sys +from pathlib import Path +from typing import Optional +import re +import subprocess + +from ns_installer import DEFAULT_LOCK_DIR, ROOT +from ns_installer.core import install_all, install_core, repin +from ns_installer.doctor import main as doctor_main +from ns_installer.methods_registry import discover_method_entrypoints, install_methods, install_single_method +from ns_installer.patches import apply_extra_patches, apply_repo_patches + + +MSVC_MODE_CHOICES = ["", "auto", "14.38", "14", "system"] +CUDA_MODE_CHOICES = ["vanilla", "experimental-env"] + + +def _add_common_build_args(parser: argparse.ArgumentParser) -> None: + parser.add_argument("--msvc-mode", default=None, choices=MSVC_MODE_CHOICES) + parser.add_argument( + "--cuda-mode", + default=None, + choices=CUDA_MODE_CHOICES, + help="CUDA mode: 'vanilla' (default, force CUDA 11.8) or 'experimental-env' (use system CUDA).", + ) + + +def _resolve_lock_dir(value: str) -> Path: + return Path(value).expanduser().resolve() + + +def _resolve_msvc_mode(args: argparse.Namespace) -> str: + return getattr(args, "msvc_mode", None) or getattr(args, "global_msvc_mode", "auto") or "auto" + + +def _resolve_cuda_mode(args: argparse.Namespace) -> str: + return getattr(args, "cuda_mode", None) or getattr(args, "global_cuda_mode", "vanilla") or "vanilla" + + +def _print_compat_completion(shell: str) -> int: + """ + Compatibility shim for tools that expect Tyro-style completion flags. + + We are argparse-based, not Tyro-based, so we generate completion output + through shtab if available. This is enough for ns-install-cli, which only + expects the command to succeed and print a shell completion script. + """ + shell = (shell or "").strip().lower() + if shell not in {"bash", "zsh"}: + raise SystemExit(f"Unsupported completion shell: {shell}") + + parser = build_parser() + + try: + import shtab # type: ignore + except Exception as e: + raise SystemExit( + "Completion generation requires 'shtab'. Install it with: pip install shtab" + ) from e + + print(shtab.complete(parser, shell=shell)) + return 0 + + +def _maybe_handle_tyro_completion(argv: Optional[list[str]]) -> Optional[int]: + args = list(sys.argv[1:] if argv is None else argv) + if not args: + return None + + if args[0] == "--tyro-print-completion": + if len(args) < 2: + raise SystemExit("--tyro-print-completion requires a shell name") + return _print_compat_completion(args[1]) + + return None + +def _extract_methods_from_ns_train_help(text: str) -> list[str]: + """ + Parse `ns-train --help` output and extract the method subcommand names. + + We look for the usage block: + usage: ns-train [-h] {a,b,c,...} + + and parse the comma-separated items inside the braces. + """ + match = re.search(r"usage:\s*ns-train\s+\[-h\]\s*\{([^}]*)\}", text, flags=re.IGNORECASE | re.DOTALL) + if not match: + return [] + + raw = match.group(1) + parts = [p.strip() for p in raw.replace("\n", "").split(",")] + methods = [p for p in parts if p and not p.startswith("...")] + return sorted(dict.fromkeys(methods)) + + +def discover_all_trainable_methods() -> dict[str, list[str] | str]: + """ + Ask the actual ns-train CLI what methods are available in the current environment. + This includes built-in nerfstudio methods and installed external/plugin methods. + """ + cmd_variants = [ + ["ns-train", "--help"], + [sys.executable, "-m", "nerfstudio.scripts.train", "--help"], + ] + + last_error = None + for cmd in cmd_variants: + try: + proc = subprocess.run( + cmd, + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + check=False, + ) + output = (proc.stdout or "") + "\n" + (proc.stderr or "") + methods = _extract_methods_from_ns_train_help(output) + if methods: + return { + "source": "ns-train --help", + "methods": methods, + } + last_error = f"Could not parse methods from command: {' '.join(cmd)}" + except Exception as e: + last_error = f"{type(e).__name__}: {e}" + + return { + "source": "unavailable", + "methods": [], + "error": last_error or "Unknown error", + } + +def build_parser() -> argparse.ArgumentParser: + p = argparse.ArgumentParser("ns-install") + + p.add_argument("--lock-dir", default=str(DEFAULT_LOCK_DIR)) + p.add_argument("--msvc-mode", dest="global_msvc_mode", default="auto", choices=MSVC_MODE_CHOICES) + p.add_argument("--cuda-mode", dest="global_cuda_mode", default="vanilla", choices=CUDA_MODE_CHOICES) + + sub = p.add_subparsers(dest="cmd", required=True) + + core_p = sub.add_parser("core") + _add_common_build_args(core_p) + + methods_p = sub.add_parser("methods") + _add_common_build_args(methods_p) + + methods_list_p = sub.add_parser( + "methods-list", + help="List methods visible in the current environment", + ) + methods_list_p.add_argument( + "--source", + choices=["available", "discovered", "both"], + default="available", + help=( + "'available' = parse ns-train --help (best view of what can actually be trained), " + "'discovered' = Python entry points only, " + "'both' = show both." + ), + ) + methods_list_p.add_argument( + "--verbose", + action="store_true", + help="Show additional details such as entry point targets.", + ) + + method_p = sub.add_parser("method") + method_p.add_argument("name") + _add_common_build_args(method_p) + + all_p = sub.add_parser("all") + _add_common_build_args(all_p) + + repin_p = sub.add_parser("repin") + repin_p.add_argument("--skip-conda", action="store_true") + repin_p.add_argument("--force-conda", action="store_true") + _add_common_build_args(repin_p) + + doctor_p = sub.add_parser("doctor", help="Inspect environment") + doctor_p.add_argument("--json", action="store_true") + _add_common_build_args(doctor_p) + return p + + +def main(argv: Optional[list[str]] = None) -> int: + compat_rc = _maybe_handle_tyro_completion(argv) + if compat_rc is not None: + return compat_rc + + parser = build_parser() + args = parser.parse_args(argv) + + lock_dir = _resolve_lock_dir(args.lock_dir) + msvc_mode = _resolve_msvc_mode(args) + cuda_mode = _resolve_cuda_mode(args) + + if args.cmd == "core": + return int(install_core(lock_dir, msvc_mode) or 0) + + if args.cmd == "methods": + install_methods(ROOT, lock_dir=lock_dir, msvc_mode=msvc_mode, cuda_mode=cuda_mode) + return 0 + + if args.cmd == "methods-list": + source = getattr(args, "source", "available") + + if source in {"discovered", "both"}: + discovered = discover_method_entrypoints() + else: + discovered = {} + + if source in {"available", "both"}: + available_info = discover_all_trainable_methods() + available = available_info.get("methods", []) + else: + available_info = {"source": "disabled"} + available = [] + + if source == "discovered": + if not discovered: + print("[INFO] No nerfstudio method entrypoints discovered in this environment.") + return 0 + + print("[INFO] Methods discovered via nerfstudio.method_configs entry points:") + for name in sorted(discovered): + if getattr(args, "verbose", False): + print(f" - {name}: {discovered[name]}") + else: + print(f" - {name}") + return 0 + + if source == "available": + if not available: + print("[WARN] Could not determine available methods from ns-train.") + if "error" in available_info: + print(f"[WARN] {available_info['error']}") + return 1 + + print(f"[INFO] Methods currently available through ns-train ({available_info['source']}):") + for name in available: + print(f" - {name}") + return 0 + + # source == "both" + print("[INFO] Methods currently available through ns-train:") + if available: + for name in available: + print(f" - {name}") + else: + print(" (none detected)") + if "error" in available_info: + print(f"[WARN] {available_info['error']}") + + print() + print("[INFO] Methods discovered via nerfstudio.method_configs entry points:") + if discovered: + for name in sorted(discovered): + if getattr(args, "verbose", False): + print(f" - {name}: {discovered[name]}") + else: + print(f" - {name}") + else: + print(" (none detected)") + + if available: + available_set = set(available) + discovered_set = set(discovered.keys()) + only_available = sorted(available_set - discovered_set) + only_discovered = sorted(discovered_set - available_set) + + if only_available: + print() + print("[INFO] Available in ns-train but not entrypoint-discovered:") + for name in only_available: + print(f" - {name}") + + if only_discovered: + print() + print("[INFO] Entrypoint-discovered but not shown by ns-train:") + for name in only_discovered: + print(f" - {name}") + + return 0 + + if args.cmd == "method": + install_single_method(args.name, ROOT, lock_dir=lock_dir, msvc_mode=msvc_mode, cuda_mode=cuda_mode) + return 0 + + if args.cmd == "all": + return int(install_all(lock_dir, msvc_mode) or 0) + + if args.cmd == "repin": + return int(repin(lock_dir, msvc_mode=msvc_mode) or 0) + + if args.cmd == "doctor": + doctor_argv = ["--lock-dir", str(lock_dir), "--msvc-mode", msvc_mode] + if getattr(args, "json", False): + doctor_argv.append("--json") + return int(doctor_main(doctor_argv) or 0) + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) \ No newline at end of file diff --git a/ns_installer/core.py b/ns_installer/core.py new file mode 100644 index 0000000000..b067b2e045 --- /dev/null +++ b/ns_installer/core.py @@ -0,0 +1,245 @@ +from __future__ import annotations + +import argparse +import os +import sys +from pathlib import Path + +from ns_installer import DEFAULT_LOCK_DIR, ROOT +from ns_installer.bootstrap import ( + build_bootstrap_context, + validate_msvc_from_shell, + which, +) +from ns_installer.build import ( + choose_conda_restore_cmd, + current_tcnn_arch, + ensure_numpy_stable, + install_av, + install_deferred, + install_packaging_base, + install_pyg_wheels, + install_remaining_from_full_lock, + install_requirements_file, + install_tcnn, + install_torch_preinstall, + print_strict_alignment_status, + repin_after_method_install, +) +from ns_installer.locks import ( + DEFAULT_NUMPY, + export_locks, + find_conda_lock, + load_build_plan, + load_installer_selection, + normalize_lines, + normalize_pkg_line, + replay_pip_filename, + split_pip_lock, + pip_lock_filename, + read_text, +) +from ns_installer.patches import apply_extra_patches +from ns_installer.methods_registry import ( + discover_method_entrypoints, + install_methods, + install_single_method, + known_method_names, +) + +from ns_installer.doctor import main as doctor_main + + +def diff_summary(expected: list[str], current: list[str], label: str) -> tuple[bool, str]: + if expected == current: + return True, f"[OK] {label} matches lock exactly." + expected_set = set(expected) + current_set = set(current) + missing = sorted(expected_set - current_set) + extra = sorted(current_set - expected_set) + lines = [f"[FAIL] {label} differs from lock."] + if missing: + lines.append(" Missing/changed (first 10):") + lines.extend([f" - {x}" for x in missing[:10]]) + if extra: + lines.append(" Extra/different (first 10):") + lines.extend([f" + {x}" for x in extra[:10]]) + return False, "\n".join(lines) + + +def normalized_current_pip_lines() -> list[str]: + import subprocess + import sys + from ns_installer.bootstrap import run + + try: + cp = run([sys.executable, "-m", "pip", "freeze", "--all"]) + except subprocess.CalledProcessError: + cp = run([sys.executable, "-m", "pip", "freeze"]) + return [normalize_pkg_line(x) for x in normalize_lines(cp.stdout, kind="pip")] + +def check_locks(lock_dir: Path, conda_exe: str | None = None) -> int: + from ns_installer.bootstrap import run + + ok = True + conda_lock = find_conda_lock(lock_dir) + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + + if conda_lock and conda_exe and os.environ.get("CONDA_PREFIX"): + current = run([conda_exe, "list", "--explicit", "--md5"]).stdout + good, msg = diff_summary( + normalize_lines(read_text(conda_lock), kind="conda"), + normalize_lines(current, kind="conda"), + "Conda explicit lock", + ) + print(msg) + ok &= good + + pip_lock = pip_lock_filename(lock_dir) + if pip_lock.exists(): + current = normalized_current_pip_lines() + good, msg = diff_summary( + [normalize_pkg_line(x) for x in normalize_lines(read_text(pip_lock), kind="pip")], + current, + "pip freeze lock", + ) + print(msg) + ok &= good + + return 0 if ok else 2 + + +def repin( + lock_dir: Path, + *, + skip_conda: bool = False, + force_conda: bool = False, + conda_exe: str | None = None, + msvc_mode: str = "", +) -> int: + conda_lock = find_conda_lock(lock_dir) + if conda_lock and not skip_conda: + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + if force_conda and conda_exe and os.environ.get("CONDA_PREFIX"): + from ns_installer.bootstrap import print_run + print_run(choose_conda_restore_cmd(conda_exe, conda_lock)) + + installer = load_installer_selection(lock_dir) + effective_msvc = str( + installer.get("preferred_msvc") or msvc_mode or os.environ.get("PREFERRED_MSVC") or "" + ).strip() + + ctx = build_bootstrap_context(lock_dir, effective_msvc) + ok, errors = validate_msvc_from_shell(lock_dir, ctx) + if not ok: + for err in errors: + print(f"[ERR] {err}") + return 2 + + pip_lock = replay_pip_filename(lock_dir) + pip_lock = pip_lock if pip_lock.exists() else pip_lock_filename(lock_dir) + if not pip_lock.exists(): + print("[INFO] No pip lock found; nothing to repin.") + return 0 + + plan = load_build_plan(lock_dir) + numpy_spec = plan.get("numpy_stable") or DEFAULT_NUMPY + tcnn_arch = str((plan.get("tinycudann") or {}).get("cuda_arch", "")).strip() or current_tcnn_arch() + + torch_lines, pyg_lines, tcnn_line, bulk, deferred, av_lines = split_pip_lock(read_text(pip_lock), lock_dir) + + state: dict = {} + install_packaging_base(lock_dir, effective_msvc) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="bootstrap") + install_torch_preinstall(lock_dir, effective_msvc, torch_lines, numpy_spec, state) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-torch") + install_pyg_wheels(lock_dir, effective_msvc, torch_lines, pyg_lines) + install_tcnn(lock_dir, effective_msvc, tcnn_line, tcnn_arch) + install_requirements_file(lock_dir, effective_msvc, bulk, lock_dir / ".tmp-bulk-install.txt") + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-bulk") + install_remaining_from_full_lock(lock_dir, effective_msvc) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-full-remaining") + install_deferred(lock_dir, effective_msvc, deferred) + ensure_numpy_stable(lock_dir, effective_msvc, numpy_spec, state, reason="post-deferred") + install_av(lock_dir, effective_msvc, av_lines) + repin_after_method_install(lock_dir, effective_msvc) + print_strict_alignment_status(lock_dir) + return 0 + + +def install_core(lock_dir: Path = DEFAULT_LOCK_DIR, msvc_mode: str = "") -> int: + apply_extra_patches(ROOT) + return repin(lock_dir, skip_conda=True, msvc_mode=msvc_mode) + + +def install_all(lock_dir: Path = DEFAULT_LOCK_DIR, msvc_mode: str = "") -> int: + rc = install_core(lock_dir, msvc_mode) + if rc != 0: + return rc + install_methods(root=ROOT, lock_dir=lock_dir, msvc_mode=msvc_mode) + return 0 + + +def main(argv: list[str] | None = None) -> int: + p = argparse.ArgumentParser("deps_lock/core wrapper") + p.add_argument("--lock-dir", default=str(DEFAULT_LOCK_DIR)) + p.add_argument("--conda-exe", default=os.environ.get("CONDA_EXE")) + p.add_argument("--msvc-mode", default="", choices=["", "auto", "14.38", "14", "system"]) + + sub = p.add_subparsers(dest="cmd", required=True) + sub.add_parser("export") + sub.add_parser("check") + + rep = sub.add_parser("repin") + rep.add_argument("--skip-conda", action="store_true") + rep.add_argument("--force-conda", action="store_true") + + sub.add_parser("core") + sub.add_parser("patches") + sub.add_parser("all") + + m = sub.add_parser("method") + m.add_argument("name") + + doc = sub.add_parser("doctor") + doc.add_argument("--json", action="store_true") + + args = p.parse_args(argv) + lock_dir = Path(args.lock_dir).resolve() + + if args.cmd == "export": + return export_locks(lock_dir, conda_exe=args.conda_exe, msvc_mode=args.msvc_mode) + + if args.cmd == "check": + return check_locks(lock_dir, conda_exe=args.conda_exe) + + if args.cmd == "repin": + return repin( + lock_dir, + skip_conda=args.skip_conda, + force_conda=args.force_conda, + conda_exe=args.conda_exe, + msvc_mode=args.msvc_mode, + ) + + if args.cmd == "core": + return install_core(lock_dir, args.msvc_mode) + + if args.cmd == "patches": + apply_extra_patches(ROOT) + return 0 + + if args.cmd == "method": + install_single_method(args.name, root=ROOT, lock_dir=lock_dir, msvc_mode=args.msvc_mode) + return 0 + + if args.cmd == "all": + return install_all(lock_dir, args.msvc_mode) + + if args.cmd == "doctor": + doctor_args = ["--lock-dir", str(lock_dir), "--msvc-mode", args.msvc_mode] + if args.json: + doctor_args.append("--json") + return doctor_main(doctor_args) + + return 0 \ No newline at end of file diff --git a/ns_installer/deps_lock.py b/ns_installer/deps_lock.py new file mode 100644 index 0000000000..6345e1e9fe --- /dev/null +++ b/ns_installer/deps_lock.py @@ -0,0 +1,7 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +from ns_installer.core import main + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/ns_installer/doctor.py b/ns_installer/doctor.py new file mode 100644 index 0000000000..4510924b68 --- /dev/null +++ b/ns_installer/doctor.py @@ -0,0 +1,65 @@ +from __future__ import annotations + +import argparse +import json +from pathlib import Path + +from ns_installer import DEFAULT_LOCK_DIR +from ns_installer.bootstrap import ( + build_bootstrap_context, + build_bootstrap_env, + find_header_in_include, + validate_msvc_from_shell, + write_bootstrap_env_snapshot, +) +from ns_installer.locks import load_build_plan + + +def diagnose(lock_dir: Path, msvc_mode: str = "") -> dict: + ctx = build_bootstrap_context(lock_dir, msvc_mode) + ok, errors = validate_msvc_from_shell(lock_dir, ctx) + env = build_bootstrap_env(lock_dir, msvc_mode) + snapshot = write_bootstrap_env_snapshot(lock_dir, env) + + include_value = env.get("INCLUDE", "") + result = { + "ok": ok, + "errors": errors, + "selected_toolset": (ctx.get("selected") or {}).get("toolset_full", ""), + "cuda_root": ctx.get("cuda_root", ""), + "include_present": bool(include_value), + "lib_present": bool(env.get("LIB", "")), + "libpath_present": bool(env.get("LIBPATH", "")), + "corecrt_h": find_header_in_include(include_value, "corecrt.h"), + "windows_h": find_header_in_include(include_value, "Windows.h"), + "bootstrap_snapshot": str(snapshot), + "build_plan": load_build_plan(lock_dir), + } + return result + + +def main(argv: list[str] | None = None) -> int: + p = argparse.ArgumentParser("ns-install doctor") + p.add_argument("--json", action="store_true") + p.add_argument("--lock-dir", default=str(DEFAULT_LOCK_DIR)) + p.add_argument("--msvc-mode", default="") + args = p.parse_args(argv) + + result = diagnose(Path(args.lock_dir), args.msvc_mode) + + if args.json: + print(json.dumps(result, indent=2)) + else: + print(f"[OK] {result['ok']}") + print(f"[MSVC] {result['selected_toolset'] or 'system'}") + print(f"[CUDA] {result['cuda_root'] or 'missing'}") + print(f"[INCLUDE] {'present' if result['include_present'] else 'missing'}") + print(f"[LIB] {'present' if result['lib_present'] else 'missing'}") + print(f"[LIBPATH] {'present' if result['libpath_present'] else 'missing'}") + print(f"[corecrt.h] {result['corecrt_h'] or 'missing'}") + print(f"[Windows.h] {result['windows_h'] or 'missing'}") + print(f"[bootstrap snapshot] {result['bootstrap_snapshot']}") + for err in result["errors"]: + print(f"[ERR] {err}") + + return 0 if result["ok"] else 2 \ No newline at end of file diff --git a/ns_installer/locks.py b/ns_installer/locks.py new file mode 100644 index 0000000000..7bfcf29980 --- /dev/null +++ b/ns_installer/locks.py @@ -0,0 +1,340 @@ +from __future__ import annotations + +import json +import os +import platform +import re +from datetime import datetime, timezone +from pathlib import Path +from typing import Optional + +from ns_installer import DEFAULT_LOCK_DIR +from ns_installer.protected import ( + NERFSTUDIO_CORE_OVERRIDES, + NERFSTUDIO_METHODS_PROTECTED, + is_core_override_name, + is_protected_method_name, +) + +DEFAULT_NUMPY = "numpy==1.26.4" +DEFAULT_TORCH = ["torch==2.1.2+cu118", "torchvision==0.16.2+cu118"] +TORCH_INDEX = "https://download.pytorch.org/whl/cu118" +PYG_INDEX_TEMPLATE = "https://data.pyg.org/whl/{torch_tag}.html" + +TORCH_LINE_RE = re.compile(r"^(torch|torchvision|torchaudio)==", re.I) +PYG_LINE_RE = re.compile(r"^torch[-_](scatter|sparse|cluster|spline[-_]conv)==", re.I) +AV_LINE_RE = re.compile(r"^av==", re.I) +PYWIN32_BAD_RE = re.compile(r"^pywin32==305\.1$", re.I) +TCNN_REQ_RE = re.compile(r"^(tinycudann|tiny-cuda-nn)(==|\s*@\s*)", re.I) + +SKIP_PATTERNS = [ + re.compile(r"^-e\s+\.", re.I), + re.compile(r"^-e\s+.+nerfstudio", re.I), + re.compile(r"^\S+\s*@\s*file:///", re.I), + re.compile(r"^cuda_backend==", re.I), + re.compile(r"^av==", re.I), + re.compile(r"^torch==", re.I), + re.compile(r"^torchvision==", re.I), + re.compile(r"^torchaudio==", re.I), + re.compile(r"^torch[-_]scatter==", re.I), + re.compile(r"^torch[-_]sparse==", re.I), + re.compile(r"^torch[-_]cluster==", re.I), + re.compile(r"^torch[-_]spline[-_]conv==", re.I), + re.compile(r"^numpy(==|<|<=|>=|>|~=)", re.I), +] +DEFER_PATTERNS = [ + re.compile(r"^tinycudann\s*@\s*git\+https://github.com/NVlabs/tiny-cuda-nn/", re.I), + re.compile(r"^tiny-cuda-nn\s*@\s*git\+https://github.com/NVlabs/tiny-cuda-nn/", re.I), + re.compile(r"^tinycudann==", re.I), + re.compile(r"^tiny-cuda-nn==", re.I), +] + +def ensure_dir(path: Path) -> None: + path.mkdir(parents=True, exist_ok=True) + +def write_text(path: Path, text: str) -> None: + ensure_dir(path.parent) + path.write_text(text, encoding="utf-8", newline="\n") + +def read_text(path: Path) -> str: + return path.read_text(encoding="utf-8-sig") + +def load_json(path: Path) -> dict: + if not path.exists(): + return {} + try: + return json.loads(read_text(path)) + except Exception: + return {} + +def current_platform_guess() -> str: + sysname = platform.system().lower() + machine = platform.machine().lower() + if sysname == "windows": + return "win-arm64" if machine in {"arm64", "aarch64"} else "win-64" + if sysname == "linux": + return "linux-aarch64" if machine in {"arm64", "aarch64"} else "linux-64" + if sysname == "darwin": + return "osx-arm64" if machine in {"arm64", "aarch64"} else "osx-64" + return f"{sysname}-{machine}" + +def conda_explicit_filename(lock_dir: Path, platform_tag: str) -> Path: return lock_dir / f"conda-explicit-{platform_tag}.txt" +def pip_lock_filename(lock_dir: Path) -> Path: return lock_dir / "pip-freeze-all.txt" +def replay_pip_filename(lock_dir: Path) -> Path: return lock_dir / "pip-freeze-replay.txt" +def build_plan_filename(lock_dir: Path) -> Path: return lock_dir / "build-plan.json" +def meta_filename(lock_dir: Path) -> Path: return lock_dir / "lock-meta.json" +def numpy_audit_filename(lock_dir: Path) -> Path: return lock_dir / "numpy-compat-audit.txt" +def nerfstudio_methods_filename(lock_dir: Path) -> Path: return lock_dir / "nerfstudio-methods-protected.json" +def nerfstudio_core_overrides_filename(lock_dir: Path) -> Path: return lock_dir / "nerfstudio-core-overrides.json" +def msvc_log_filename(lock_dir: Path) -> Path: return lock_dir / "msvc-toolsets.txt" +def msvc_selected_filename(lock_dir: Path) -> Path: return lock_dir / "msvc-selected.txt" +def installer_selection_filename(lock_dir: Path) -> Path: return lock_dir / "installer-selection.json" + +def load_build_plan(lock_dir: Path) -> dict: + return load_json(build_plan_filename(lock_dir)) + +def load_installer_selection(lock_dir: Path) -> dict: + return load_json(installer_selection_filename(lock_dir)) + +def normalize_lines(text: str, *, kind: str) -> list[str]: + out: list[str] = [] + for raw in text.replace("\r\n", "\n").replace("\r", "\n").split("\n"): + line = raw.strip() + if not line or line.startswith("#"): + continue + if kind == "pip" and (line.startswith("-e ") or line.startswith("--editable")): + continue + out.append(line) + return out + +def normalize_pkg_line(line: str) -> str: + line = line.strip() + return "pywin32==305" if PYWIN32_BAD_RE.match(line) else line + +def parse_name(line: str) -> str: + if " @ " in line: + return line.split(" @ ", 1)[0].strip().lower().replace("_", "-") + for sep in ("==", "<=", ">=", "~=", "<", ">"): + if sep in line: + return line.split(sep, 1)[0].strip().lower().replace("_", "-") + return line.strip().lower().replace("_", "-") + +def detect_torch_lines(lines: list[str]) -> list[str]: + found = [normalize_pkg_line(line) for line in lines if TORCH_LINE_RE.match(line)] + if not found: + return DEFAULT_TORCH[:] + uniq: list[str] = [] + for line in found: + if line not in uniq: + uniq.append(line) + return uniq + +def detect_pyg_lines(lines: list[str]) -> list[str]: + uniq: list[str] = [] + for line in lines: + line = normalize_pkg_line(line) + if PYG_LINE_RE.match(line) and line not in uniq: + uniq.append(line) + return uniq + +def detect_numpy_baseline(lines: list[str]) -> str: + for line in lines: + if line.lower().startswith("numpy=="): + version = line.split("==", 1)[1].strip() + if version and not version.startswith("2"): + return f"numpy=={version}" + return DEFAULT_NUMPY + +def detect_tcnn_line(lines: list[str]) -> str: + for line in lines: + if TCNN_REQ_RE.match(line): + return normalize_pkg_line(line) + return "git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch" + +def compute_replay_lines(lines: list[str]) -> list[str]: + replay: list[str] = [] + for raw in lines: + line = normalize_pkg_line(raw) + name = parse_name(line) + if is_protected_method_name(name) or is_core_override_name(name): + continue + if any(p.search(line) for p in SKIP_PATTERNS): + continue + if any(p.search(line) for p in DEFER_PATTERNS): + continue + replay.append(line) + return replay + +def split_pip_lock(lock_text: str, lock_dir: Path) -> tuple[list[str], list[str], str, list[str], list[str], list[str]]: + lines = [normalize_pkg_line(x) for x in normalize_lines(lock_text, kind="pip")] + plan = load_build_plan(lock_dir) + torch_lines = plan.get("torch_preinstall") or detect_torch_lines(lines) + pyg_lines = plan.get("pyg_wheels") or detect_pyg_lines(lines) + tcnn_line = (plan.get("tinycudann") or {}).get("requirement") or detect_tcnn_line(lines) + torch_names = {parse_name(x) for x in torch_lines} + pyg_names = {parse_name(x) for x in pyg_lines} + bulk, deferred, av_lines = [], [], [] + for line in lines: + name = parse_name(line) + if name in torch_names or name in pyg_names or name == "numpy": + continue + if is_protected_method_name(name) or is_core_override_name(name): + continue + if name in {"tinycudann", "tiny-cuda-nn"}: + continue + if AV_LINE_RE.match(line): + av_lines.append(line) + continue + if any(p.search(line) for p in DEFER_PATTERNS): + deferred.append(line) + continue + if any(p.search(line) for p in SKIP_PATTERNS): + continue + bulk.append(line) + return torch_lines, pyg_lines, tcnn_line, bulk, deferred, av_lines + +def find_conda_lock(lock_dir: Path) -> Optional[Path]: + matches = sorted(lock_dir.glob("conda-explicit-*.txt")) + if matches: + platform_tag = current_platform_guess() + platform_match = lock_dir / f"conda-explicit-{platform_tag}.txt" + if platform_match.exists(): + return platform_match + return matches[0] + fallback = lock_dir / "conda-explicit.txt" + return fallback if fallback.exists() else None + +def parse_platform_from_explicit(explicit_text: str) -> str: + for line in explicit_text.splitlines(): + m = re.match(r"\s*#\s*platform:\s*(\S+)", line) + if m: + return m.group(1) + return current_platform_guess() + +def export_nerfstudio_methods(lock_dir: Path, lines: list[str]) -> None: + installed: dict[str, dict] = {} + for raw in lines: + line = normalize_pkg_line(raw) + name = parse_name(line) + if not is_protected_method_name(name): + continue + for key, spec in NERFSTUDIO_METHODS_PROTECTED.items(): + if name in spec["pip_names"]: + installed[key] = { + "locked_requirement": line, + "install_ref": spec["install_ref"], + "patch_rel": spec["patch_rel"], + "pip_names": sorted(spec["pip_names"]), + "category": spec.get("category", "method"), + } + break + payload = {"protected_methods": { + key: { + "install_ref": spec["install_ref"], + "patch_rel": spec["patch_rel"], + "pip_names": sorted(spec["pip_names"]), + "category": spec.get("category", "method"), + "locked_requirement": installed.get(key, {}).get("locked_requirement", ""), + "present_in_lock": key in installed, + } for key, spec in NERFSTUDIO_METHODS_PROTECTED.items() + }} + write_text(nerfstudio_methods_filename(lock_dir), json.dumps(payload, indent=2) + "\n") + +def export_nerfstudio_core_overrides(lock_dir: Path, lines: list[str]) -> None: + installed: dict[str, dict] = {} + for raw in lines: + line = normalize_pkg_line(raw) + name = parse_name(line) + if not is_core_override_name(name): + continue + for key, spec in NERFSTUDIO_CORE_OVERRIDES.items(): + if name in spec["pip_names"]: + installed[key] = { + "locked_requirement": line, + "install_ref": spec["install_ref"], + "patch_rel": spec["patch_rel"], + "pip_names": sorted(spec["pip_names"]), + "category": spec.get("category", "core_dependency"), + "enforce_as_standard": bool(spec.get("enforce_as_standard", False)), + } + break + payload = {"core_overrides": { + key: { + "install_ref": spec["install_ref"], + "patch_rel": spec["patch_rel"], + "pip_names": sorted(spec["pip_names"]), + "category": spec.get("category", "core_dependency"), + "enforce_as_standard": bool(spec.get("enforce_as_standard", False)), + "locked_requirement": installed.get(key, {}).get("locked_requirement", ""), + "present_in_lock": key in installed, + } for key, spec in NERFSTUDIO_CORE_OVERRIDES.items() + }} + write_text(nerfstudio_core_overrides_filename(lock_dir), json.dumps(payload, indent=2) + "\n") + +def export_numpy_audit(lock_dir: Path, lines: list[str], plan: dict) -> None: + rows = [] + for line in lines: + name = parse_name(line) + if name.startswith("numpy") or name in {"torch", "torchvision", "torchaudio", "opencv-python", "opencv-contrib-python", "matplotlib", "scipy", "pandas", "pycolmap", "open3d", "tensorflow"}: + rows.append(line) + rows.extend([f"PLAN torch_preinstall: {x}" for x in plan.get("torch_preinstall", [])]) + rows.extend([f"PLAN pyg_wheels: {x}" for x in plan.get("pyg_wheels", [])]) + rows.extend([f"PLAN deferred: {x}" for x in plan.get("deferred", [])]) + write_text(numpy_audit_filename(lock_dir), "\n".join(dict.fromkeys(rows)) + "\n") + +def export_locks(lock_dir: Path, conda_exe: str | None = None, msvc_mode: str = "") -> int: + from ns_installer.bootstrap import build_bootstrap_context, run, which, write_msvc_log + ensure_dir(lock_dir) + conda_exe = conda_exe or os.environ.get("CONDA_EXE") or which("conda") or which("conda.bat") + platform_tag = current_platform_guess() + conda_lock_path: Optional[Path] = None + if conda_exe and os.environ.get("CONDA_PREFIX"): + cp = run([conda_exe, "list", "--explicit", "--md5"]) + explicit = cp.stdout + platform_tag = parse_platform_from_explicit(explicit) + conda_lock_path = conda_explicit_filename(lock_dir, platform_tag) + write_text(conda_lock_path, explicit) + cp_json = run([conda_exe, "list", "--json"]) + write_text(lock_dir / "conda-list.json", cp_json.stdout) + pip_cp = run([os.sys.executable, "-m", "pip", "freeze", "--all"], check=False) + pip_lines = [normalize_pkg_line(x) for x in normalize_lines(pip_cp.stdout, kind="pip")] + write_text(pip_lock_filename(lock_dir), "\n".join(pip_lines) + "\n") + write_text(replay_pip_filename(lock_dir), "\n".join(compute_replay_lines(pip_lines)) + "\n") + installer = load_installer_selection(lock_dir) + effective_msvc = str(installer.get("preferred_msvc") or msvc_mode or os.environ.get("PREFERRED_MSVC") or "").strip() + ctx = build_bootstrap_context(lock_dir, effective_msvc) + plan = { + "numpy_stable": detect_numpy_baseline(pip_lines), + "torch_preinstall": detect_torch_lines(pip_lines), + "torch_index": TORCH_INDEX, + "pyg_wheels": detect_pyg_lines(pip_lines), + "pyg_index_template": PYG_INDEX_TEMPLATE, + "tinycudann": { + "requirement": detect_tcnn_line(pip_lines), + "cuda_arch": str(installer.get("cuda_arch") or "").strip(), + }, + "deferred": [x for x in pip_lines if any(p.search(x) for p in DEFER_PATTERNS)], + "preferred_msvc": effective_msvc, + "bootstrap_mode": "subprocess-shell-bootstrap", + "selected_toolset": (ctx.get("selected") or {}).get("toolset_full", ""), + "selected_installation": (ctx.get("selected") or {}).get("installation", ""), + "cuda_root": ctx.get("cuda_root", ""), + "materialized_include": (ctx.get("materialized_env") or {}).get("INCLUDE", ""), + "materialized_lib": (ctx.get("materialized_env") or {}).get("LIB", ""), + "materialized_libpath": (ctx.get("materialized_env") or {}).get("LIBPATH", ""), + } + write_text(build_plan_filename(lock_dir), json.dumps(plan, indent=2) + "\n") + export_numpy_audit(lock_dir, pip_lines, plan) + export_nerfstudio_methods(lock_dir, pip_lines) + export_nerfstudio_core_overrides(lock_dir, pip_lines) + write_msvc_log(lock_dir) + meta = { + "created_utc": datetime.now(timezone.utc).isoformat(), + "platform_guess": platform_tag, + "conda_lock": conda_lock_path.name if conda_lock_path else None, + "pip_lock": pip_lock_filename(lock_dir).name, + "pip_replay": replay_pip_filename(lock_dir).name, + "build_plan": build_plan_filename(lock_dir).name, + } + write_text(meta_filename(lock_dir), json.dumps(meta, indent=2) + "\n") + return 0 diff --git a/ns_installer/methods_registry.py b/ns_installer/methods_registry.py new file mode 100644 index 0000000000..8f993401ac --- /dev/null +++ b/ns_installer/methods_registry.py @@ -0,0 +1,203 @@ +from __future__ import annotations + +import importlib +from importlib.metadata import entry_points +from pathlib import Path + +from ns_installer import ROOT +from ns_installer.build import install_editable_project, maybe_build_method_native, maybe_build_method_native, repin_after_method_install +from ns_installer.patches import apply_repo_patches + + +def method_specs() -> dict[str, dict]: + return { + "splatfacto-w": { + "folder": "splatfacto-w", + "module": "splatfactow", + "entrypoint_group": "nerfstudio.method_configs", + "preferred_repo": "https://github.com/BlockFrank/splatfacto-w_reforged", + "upstream_repo": "https://github.com/BlockFrank/splatfacto-w_reforged", + "patch_rel": "splatfacto-w", + "needs_cpp_build": False, + "windows_build": None, + "post_install_repin": False, + }, + "zipnerf": { + "folder": "zipnerf-pytorch", + "module": "zipnerf_ns", + "entrypoint_group": "nerfstudio.method_configs", + "preferred_repo": "https://github.com/SuLvXiangXin/zipnerf-pytorch.git", + "upstream_repo": "https://github.com/SuLvXiangXin/zipnerf-pytorch.git", + "patch_rel": "zipnerf-pytorch", + "needs_cpp_build": True, + "windows_build": "zipnerf_cuda", + "post_install_repin": False, + }, + "tetra-nerf": { + "folder": "tetra-nerf", + "module": "tetranerf", + "entrypoint_group": "nerfstudio.method_configs", + "preferred_repo": "https://github.com/jkulhanek/tetra-nerf", + "upstream_repo": "https://github.com/jkulhanek/tetra-nerf", + "patch_rel": "tetra-nerf", + "needs_cpp_build": True, + "windows_build": "tetra", + "post_install_repin": False, + }, + "opennerf": { + "folder": "opennerf", + "module": "opennerf", + "entrypoint_group": "nerfstudio.method_configs", + "preferred_repo": "https://github.com/opennerf/opennerf", + "upstream_repo": "https://github.com/opennerf/opennerf", + "patch_rel": "opennerf", + "needs_cpp_build": False, + "windows_build": None, + "post_install_repin": False, + }, + "igs2gs": { + "folder": "instruct-gs2gs", + "module": "igs2gs", + "entrypoint_group": "nerfstudio.method_configs", + "preferred_repo": "https://github.com/cvachha/instruct-gs2gs", + "upstream_repo": "https://github.com/cvachha/instruct-gs2gs", + "patch_rel": "igs2gs", + "needs_cpp_build": False, + "windows_build": None, + "post_install_repin": False, + }, + "lerf": { + "folder": "lerf", + "module": "lerf", + "entrypoint_group": "nerfstudio.method_configs", + "preferred_repo": "https://github.com/BlockFrank/lerf", + "upstream_repo": "https://github.com/BlockFrank/lerf", + "patch_rel": "lerf", + "needs_cpp_build": False, + "windows_build": None, + "post_install_repin": False, + }, + "NeRFtoGSandBack": { + "folder": "NeRFtoGSandBack", + "module": "nerftogsandback", + "entrypoint_group": "nerfstudio.method_configs", + "preferred_repo": "https://github.com/grasp-lyrl/NeRFtoGSandBack", + "upstream_repo": "https://github.com/grasp-lyrl/NeRFtoGSandBack", + "patch_rel": "NeRFtoGSandBack", + "needs_cpp_build": False, + "windows_build": None, + "post_install_repin": False, + }, + "relationfield": { + "folder": "relationfield", + "module": "relationfield", + "entrypoint_group": "nerfstudio.method_configs", + "preferred_repo": "https://github.com/boschresearch/RelationField.git", + "upstream_repo": "https://github.com/boschresearch/RelationField.git", + "patch_rel": "relationfield", + "needs_cpp_build": False, + "windows_build": None, + "post_install_repin": False, + }, + "pynerf": { + "folder": "pynerf", + "module": "pynerf", + "entrypoint_group": "nerfstudio.method_configs", + "preferred_repo": "https://github.com/hturki/pynerf", + "upstream_repo": "https://github.com/hturki/pynerf", + "patch_rel": "pynerf", + "needs_cpp_build": False, + "windows_build": None, + "post_install_repin": False, + }, + } + + +def known_method_names() -> list[str]: + return sorted(method_specs().keys()) + + +def discover_method_entrypoints() -> dict[str, str]: + return {ep.name: ep.value for ep in entry_points(group="nerfstudio.method_configs")} + + +def discover_dataparser_entrypoints() -> dict[str, str]: + return {ep.name: ep.value for ep in entry_points(group="nerfstudio.dataparser_configs")} + + +def install_single_method( + name: str, + root: Path | None = None, + lock_dir: Path | None = None, + msvc_mode: str = "", + cuda_mode: str = "vanilla", +) -> None: + root = root or ROOT + specs = method_specs() + + if name not in specs: + raise ValueError(f"Unknown method: {name}") + + spec = specs[name] + path = root / spec["folder"] + + if not path.exists(): + raise FileNotFoundError(f"Missing repo: {path}") + + patch_rel = spec.get("patch_rel") + if patch_rel: + apply_repo_patches(root, patch_rel) + + install_editable_project( + path, + lock_dir=lock_dir, + msvc_mode=msvc_mode, + cuda_mode=cuda_mode, + no_deps=True, + no_build_isolation=bool(spec.get("needs_cpp_build", False)), + ) + + maybe_build_method_native( + name, + path, + lock_dir=lock_dir, + msvc_mode=msvc_mode, + cuda_mode=cuda_mode, + ) + + if spec.get("post_install_repin", True) and lock_dir is not None: + print("[INFO] Running repin after method installation...") + repin_after_method_install(lock_dir, msvc_mode, cuda_mode=cuda_mode) # ✅ PATCH + print(f"[INSTALL] {name} -> {path}") + else: + print(f"[INFO] {name} Method installed successfully.") + print("[INFO] Automatic repin skipped.") + +def install_methods( + root: Path | None = None, + only: list[str] | None = None, + lock_dir: Path | None = None, + msvc_mode: str = "", + cuda_mode: str = "vanilla", +) -> None: + for name in (only or known_method_names()): + install_single_method( + name, + root=root, + lock_dir=lock_dir, + msvc_mode=msvc_mode, + cuda_mode=cuda_mode, + ) + + +def validate_method_install(name: str, root: Path | None = None) -> tuple[bool, str]: + specs = method_specs() + if name not in specs: + return False, f"Unknown method: {name}" + + module = specs[name]["module"] + try: + importlib.import_module(module) + return True, f"OK: module '{module}' importable" + except Exception as e: + return False, f"FAIL: module '{module}' not importable: {type(e).__name__}: {e}" \ No newline at end of file diff --git a/ns_installer/patches.py b/ns_installer/patches.py new file mode 100644 index 0000000000..cfb32eb5c8 --- /dev/null +++ b/ns_installer/patches.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +import filecmp +import shutil +from pathlib import Path +from typing import Iterable + +PATCHABLE_REPOS: tuple[str, ...] = ( + "lerf", + "tetra-nerf", + "zipnerf-pytorch", + "opennerf", + "NeRFtoGSandBack", + "relationfield", + "pynerf", + "splatfacto-w", + "feature-splatting", + "igs2gs", + "livescene", + "nerfplayer", +) + +SKIP_SUFFIXES: tuple[str, ...] = (".diff", ".patch", ".patched", ".tensorpatch") +SKIP_FILENAMES: set[str] = {".DS_Store", "Thumbs.db"} + +def _should_skip_patch_file(path: Path) -> bool: + return path.name in SKIP_FILENAMES or any(path.name.endswith(s) for s in SKIP_SUFFIXES) + +def _iter_patch_files(repo_patch_root: Path) -> Iterable[Path]: + for src in repo_patch_root.rglob("*"): + if src.is_dir() or _should_skip_patch_file(src): + continue + yield src + +def _safe_copy_with_backup(src: Path, dst: Path, *, create_missing: bool, make_backup: bool) -> str: + if not dst.exists(): + if not create_missing: + return "missing-target" + dst.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(src, dst) + return "created" + try: + same = filecmp.cmp(src, dst, shallow=False) + except Exception: + same = False + if same: + return "unchanged" + if make_backup: + backup = dst.with_suffix(dst.suffix + ".orig") + if not backup.exists(): + backup.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(dst, backup) + dst.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(src, dst) + return "patched" + +def list_available_patch_roots(root_dir: Path) -> list[str]: + patch_root = root_dir / "Extra-Methods-Patches" + if not patch_root.exists(): + return [] + return sorted([p.name for p in patch_root.iterdir() if p.is_dir()]) + +def apply_repo_patches(root_dir: Path, repo_name: str, *, create_missing: bool = False, make_backup: bool = True) -> int: + patch_root = root_dir / "Extra-Methods-Patches" + repo_patch_root = patch_root / repo_name + repo_real_root = root_dir / repo_name + if not repo_patch_root.exists(): + print(f"[INFO] No patch tree for repo '{repo_name}'; skipping.") + return 0 + if not repo_real_root.exists(): + print(f"[WARN] Repo root missing for patch '{repo_name}': {repo_real_root}") + return 0 + print(f"[INFO] Applying patches for repo: {repo_name}") + changed = 0 + missing = 0 + unchanged = 0 + for src in _iter_patch_files(repo_patch_root): + rel = src.relative_to(repo_patch_root) + dst = repo_real_root / rel + result = _safe_copy_with_backup(src, dst, create_missing=create_missing, make_backup=make_backup) + if result == "patched": + changed += 1 + print(f"[PATCH] {repo_name}/{rel}") + elif result == "created": + changed += 1 + print(f"[CREATE] {repo_name}/{rel}") + elif result == "unchanged": + unchanged += 1 + else: + missing += 1 + print(f"[WARN] Target missing for patch: {dst}") + print(f"[INFO] Repo '{repo_name}' done: changed={changed}, unchanged={unchanged}, missing-targets={missing}") + return changed + +def apply_extra_patches(root_dir: Path, *, create_missing: bool = False, make_backup: bool = True, include_unknown_patch_roots: bool = False) -> None: + patch_root = root_dir / "Extra-Methods-Patches" + if not patch_root.exists(): + print("[INFO] No Extra-Methods-Patches directory found; skipping.") + return + available = list_available_patch_roots(root_dir) + if not available: + print("[INFO] Extra-Methods-Patches exists but contains no patch roots; skipping.") + return + print("[INFO] Applying external patch trees...") + repo_names: list[str] = [name for name in PATCHABLE_REPOS if (patch_root / name).exists()] + if include_unknown_patch_roots: + extras = [name for name in available if name not in repo_names] + repo_names.extend(extras) + total_changed = 0 + for repo_name in repo_names: + total_changed += apply_repo_patches(root_dir, repo_name, create_missing=create_missing, make_backup=make_backup) + print(f"[INFO] External patch application complete. Total changed/created files: {total_changed}") diff --git a/ns_installer/protected.py b/ns_installer/protected.py new file mode 100644 index 0000000000..cd0490d8a9 --- /dev/null +++ b/ns_installer/protected.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +TCNN_GIT = "git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch" +PYCOLMAP_GIT = "git+https://github.com/rmbrualla/pycolmap.git" + +NERFSTUDIO_METHODS_PROTECTED = { + "feature-splatting": { + "pip_names": {"feature-splatting", "feature_splatting"}, + "install_ref": "git+https://github.com/vuer-ai/feature-splatting", + "patch_rel": "feature-splatting", + "category": "method", + }, + "igs2gs": { + "pip_names": {"igs2gs"}, + "install_ref": "git+https://github.com/cvachha/instruct-gs2gs", + "patch_rel": "igs2gs", + "category": "method", + }, + "lerf": { + "pip_names": {"lerf"}, + "install_ref": "git+https://github.com/kerrj/lerf", + "patch_rel": "lerf", + "category": "method", + }, + "livescene": { + "pip_names": {"livescene"}, + "install_ref": "git+https://github.com/Tavish9/livescene", + "patch_rel": "livescene", + "category": "method", + }, + "nerfplayer": { + "pip_names": {"nerfplayer"}, + "install_ref": "git+https://github.com/lsongx/nerfplayer-nerfstudio.git", + "patch_rel": "nerfplayer", + "category": "method", + }, + "opennerf": { + "pip_names": {"opennerf"}, + "install_ref": "git+https://github.com/opennerf/opennerf", + "patch_rel": "opennerf", + "category": "method", + }, + "pynerf": { + "pip_names": {"pynerf"}, + "install_ref": "git+https://github.com/hturki/pynerf", + "patch_rel": "pynerf", + "category": "method", + }, + "relationfield": { + "pip_names": {"relationfield"}, + "install_ref": "git+https://github.com/boschresearch/RelationField.git", + "patch_rel": "relationfield", + "category": "method", + }, + "tetra-nerf": { + "pip_names": {"tetra-nerf", "tetra_nerf"}, + "install_ref": "git+https://github.com/jkulhanek/tetra-nerf", + "patch_rel": "tetra-nerf", + "category": "method", + }, + "zipnerf-pytorch": { + "pip_names": {"zipnerf", "zipnerf-pytorch"}, + "install_ref": "git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git", + "patch_rel": "zipnerf-pytorch", + "category": "method", + }, + "splatfacto-w": { + "pip_names": {"splatfacto-w", "splatfactow"}, + "install_ref": "git+https://github.com/KevinXu02/splatfacto-w", + "patch_rel": "splatfacto-w", + "category": "method", + }, +} + +NERFSTUDIO_CORE_OVERRIDES = { + "pycolmap": { + "pip_names": {"pycolmap"}, + "install_ref": PYCOLMAP_GIT, + "patch_rel": None, + "category": "core_dependency", + "enforce_as_standard": True, + }, +} + +NERFSTUDIO_METHODS_PROTECTED_NAMES = { + alias + for spec in NERFSTUDIO_METHODS_PROTECTED.values() + for alias in spec["pip_names"] +} +NERFSTUDIO_CORE_OVERRIDE_NAMES = { + alias + for spec in NERFSTUDIO_CORE_OVERRIDES.values() + for alias in spec["pip_names"] +} + +PROTECTED_GIT_PACKAGES = { + "tinycudann": TCNN_GIT, + "tiny-cuda-nn": TCNN_GIT, + "pycolmap": PYCOLMAP_GIT, +} + +def is_protected_method_name(name: str) -> bool: + return (name or "").strip().lower().replace("_", "-") in NERFSTUDIO_METHODS_PROTECTED_NAMES + +def is_core_override_name(name: str) -> bool: + return (name or "").strip().lower().replace("_", "-") in NERFSTUDIO_CORE_OVERRIDE_NAMES diff --git a/pixi.lock b/pixi.lock deleted file mode 100644 index d4036678c0..0000000000 --- a/pixi.lock +++ /dev/null @@ -1,9105 +0,0 @@ -version: 4 -environments: - default: - channels: - - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/ - - url: https://conda.anaconda.org/nvidia/ - - url: https://conda.anaconda.org/conda-forge/ - - url: https://conda.anaconda.org/pytorch/ - packages: - linux-64: - - conda: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_kmp_llvm.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.11-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.0-hac33072_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.7.18-he0b1f16_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.6.11-heb1d5e4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.9.15-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.2.18-hce8ee76_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.4.2-h01f5eca_8.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.8.1-hdb68c23_10.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.14.7-hbfbeace_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.10.4-h50844eb_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.5.7-h6be9164_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.1.15-hce8ee76_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.1.18-hce8ee76_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.26.8-h2150271_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.267-hddb5a97_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/blas-1.0-mkl.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py310hc6cd4ac_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.28.1-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.2.2-hbcca054_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-h3faef2a_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ceres-solver-2.2.0-h30ec75d_2.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/colmap-3.9.1-cpuhe398016_3.conda - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-11.8.0-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cccl-11.8.89-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-command-line-tools-11.8.0-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-compiler-11.8.0-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cudart-11.8.89-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cudart-dev-11.8.89-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cuobjdump-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cupti-11.8.87-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cuxxfilt-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-demo-suite-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-documentation-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-driver-dev-11.8.89-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-gdb-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-libraries-11.8.0-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-libraries-dev-11.8.0-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-memcheck-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nsight-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nsight-compute-11.8.0-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvcc-11.8.89-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvdisasm-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvml-dev-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvprof-11.8.87-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvprune-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvrtc-11.8.89-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvrtc-dev-11.8.89-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvtx-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvvp-11.8.87-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-profiler-api-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-runtime-11.8.0-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-sanitizer-api-11.8.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-toolkit-11.8.0-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-tools-11.8.0-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-visual-tools-11.8.0-0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/eigen-3.4.0-h00ab1b0_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.2-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-7.0.0-gpl_hdd1146e_100.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.14.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/flann-1.9.2-h2b5ea80_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/freeimage-3.18.0-h4b96d29_20.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.10-h36c2ea0_0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/gds-tools-1.4.0.31-0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/gettext-0.22.5-h59595ed_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gettext-tools-0.22.5-h59595ed_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gflags-2.2.2-he1b5a44_1004.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/glew-2.1.0-h9c3ff4c_2.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-2.80.0-hf2295e7_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.80.0-hde27a5a_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.0-hed5481d_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-h59595ed_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.1.5-py310hc3586ac_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.7.9-hb077bed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.24.3-h9ad1361_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.24.3-haf2f30d_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-8.4.0-h3d44ed6_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.3-nompi_h4f84152_101.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/imath-3.1.11-hfc55251_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-hd590300_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.2-h659d440_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h55db66e_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240116.2-cxx17_h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-15.0.2-hefa796f_6_cpu.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-15.0.2-hbabe93e_6_cpu.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-15.0.2-hbabe93e_6_cpu.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-flight-15.0.2-hc4f8a93_6_cpu.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-flight-sql-15.0.2-he4f5ca8_6_cpu.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-gandiva-15.0.2-hc1954e9_6_cpu.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-15.0.2-he4f5ca8_6_cpu.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libasprintf-0.22.5-h661eb56_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libasprintf-devel-0.22.5-h661eb56_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.1-h8fe9dca_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-1_h86c2bf4_netlib.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.84.0-h8013b2b_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcap-2.69-h0f662aa_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-5_h92ddd45_netlib.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp15-15.0.7-default_h127d8a8_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libclang13-18.1.5-default_h5d6823c_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcublas-11.11.3.6-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcublas-dev-11.11.3.6-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcufft-10.9.0.58-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcufft-dev-10.9.0.58-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcufile-1.4.0.31-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcufile-dev-1.4.0.31-0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcurand-10.3.0.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcurand-dev-10.3.0.86-0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.7.1-hca28451_0.conda - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcusolver-11.4.1.48-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcusolver-dev-11.4.1.48-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcusparse-11.7.5.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcusparse-dev-11.7.5.86-0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.20-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.120-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.3-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-13.2.0-h77fa898_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.3-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-0.22.5-h59595ed_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-devel-0.22.5-h59595ed_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-13.2.0-h69a702a_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-13.2.0-hca663fb_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.0-hf2295e7_6.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.0-hac7e632_1003.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.23.0-h9be4e54_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.23.0-hc7a4891_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.49-h4f305b6_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.62.2-h15f2491_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.10.0-default_h2fb2949_1000.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.7-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-5_h92ddd45_netlib.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hb3ce162_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm16-16.0.6-hb3ce162_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libllvm18-18.1.5-hb77312f_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.58.0-h47da74e_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.9.0-hd590300_0.conda - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libnpp-11.8.0.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libnpp-dev-11.8.0.86-0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libnvjpeg-11.9.0.86-0.tar.bz2 - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libnvjpeg-dev-11.9.0.86-0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.0.0-h2da1b83_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.0.0-hb045406_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.0.0-hb045406_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.0.0-h5c03a75_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.0.0-h2da1b83_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.0.0-h2da1b83_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.0.0-h5c03a75_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.0.0-h07e8aee_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.0.0-h07e8aee_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.0.0-he02047a_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.0.0-h39126c6_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.0.0-he02047a_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libparquet-15.0.2-hacf5a1f_6_cpu.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.43-h2797004_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libpq-16.2-h33b98f1_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-4.25.3-h08a7969_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libraw-0.21.1-h2a13503_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2023.09.01-h5a48ba9_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc60ed4a_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.3-h2797004_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-hc0a3c3a_7.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-255-h3516f8a_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.19.0-h166bdaf_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.19.0-hb90f79a_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-h1dd3fc0_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.8.0-h166bdaf_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libva-2.21.0-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/libvpx-1.14.0-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.15-h0b41bf4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h662e7e4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.6-h232c23b_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-hd590300_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py310h2372a71_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/metis-5.1.0-h59595ed_1007.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mkl-2023.0.0-h84fe81f_26648.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.3.1-hfe3b2da_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.1-h9458935_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.6-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.3.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.3.0-hf1915f5_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.3.0-hca2cd23_4.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.9.1-h7ab15ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/networkx-3.3-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/nsight-compute-2022.3.0.22-0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/nss-3.98-h1d7d5a4_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/numpy-1.26.4-py310hb13e2d6_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.2-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.2.2-haf962dd_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openh264-2.4.1-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.0-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/orc-2.0.0-h17fec99_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.24.1-hc5aa10d_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.43-hcad00b1_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pillow-10.3.0-py310hf73ecf8_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pip-24.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/pugixml-1.14-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-17.0-hb77b528_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-15.0.2-py310hd207890_6_cpu.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.10.14-hd12c33a_0_cpython.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.10-4_cp310.conda - - conda: https://conda.anaconda.org/pytorch/linux-64/pytorch-2.2.2-py3.10_cuda11.8_cudnn8.7.0_0.tar.bz2 - - conda: https://conda.anaconda.org/pytorch/linux-64/pytorch-cuda-11.8-h7e8668a_5.tar.bz2 - - conda: https://conda.anaconda.org/pytorch/noarch/pytorch-mutex-1.0-cuda.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.1-py310h2372a71_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-hc9dc06e_21.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/rdma-core-51.0-hd3aeb46_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/re2-2023.09.01-h7f4b329_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/s2n-1.4.12-h06160fa_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.0-hdb0a2a9_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/suitesparse-5.10.1-h5a4f163_3.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.0.0-h59595ed_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/sympy-1.12-pypyh9d50eac_103.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.12.0-h00ab1b0_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - - conda: https://conda.anaconda.org/pytorch/linux-64/torchtriton-2.2.0-py310.tar.bz2 - - conda: https://conda.anaconda.org/pytorch/linux-64/torchvision-0.17.2-py310_cu118.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.11.0-pyha770c72_0.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/ucx-1.15.0-ha691c75_8.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/vlfeat-0.9.21-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/noarch/wheel-0.43.0-pyhd8ed1ab_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/x264-1!164.3095-h166bdaf_2.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/x265-3.5-h924138e_3.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h8ee46fc_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h8ee46fc_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-hd590300_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h8ee46fc_1.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.41-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-fixesproto-5.0-h7f98852_1002.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-h7391055_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.9-h8ee46fc_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-5.0.3-h7f98852_1004.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hd590300_0.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h0b41bf4_1003.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-h7f98852_1002.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 - - conda: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-hd590300_5.conda - - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda - - pypi: https://files.pythonhosted.org/packages/a2/ad/e0d3c824784ff121c03cc031f944bc7e139a8f1870ffd2845cc2dd76f6c4/absl_py-2.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6a/00/b08f23b7d7e1e14ce01419a467b583edbb93c6cdb8654e54a9cc579cd61f/addict-2.4.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ec/f7/378254e6dd7ae6f31fe40c8649eea7d4832a42243acaf0f1fff9083b2bed/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/45/86/4736ac618d82a20d87d2f92ae19441ebc7ac9e7a581d7e58bbe79233b24a/asttokens-2.4.1-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fa/9f/3c3503693386c4b0f245eaf5ca6198e3b28879ca0a40bde6b0e319793453/async_lru-2.0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e0/44/827b2a91a5816512fcaf3cc4ebc465ccd5d598c45cefa6703fcf4a79018f/attrs-23.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/50/c3/81e9efb59751b7a151c213f7976ce3bfac9a7786949947afbd60eee279df/av-12.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/14/cc/e0cce71e334a1fc4665a52bdb9b88c95952251643eb4382ad8a8954831ec/awscli-1.32.100-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/27/45/377f7e32a5c93d94cd56542349b34efab5ca3f9e2fd5a68c5e93169aa32d/Babel-2.15.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ea/63/da7237f805089ecc28a3f36bca6a21c31fcbc2eb380f3b8f1be3312abd14/bleach-6.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d3/4d/86d46c869bd32c46bce4290a6dac45ff63e92fbc034c67ccb35b6477caab/botocore-1.34.100-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fb/2b/a64c2d25a37aeb921fddb929111413049fc5f8b9a4c1aefaffaafe768d54/cachetools-5.3.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c9/7c/43d81bdd5a915923c3bad5bb4bff401ea00ccc8e28433fb6083d2e3bf58e/cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f3/18/3e867ab37a24fdf073c1617b9c7830e06ec270b1ea4694a624038fc40a03/colorlog-6.8.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/67/38/34ca2481c857c704ce2c44a78df31eed98b05558c87be097a1eb430ec332/comet_ml-3.41.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6f/b3/b4ac838711fd74a2b4e6f746703cf9dd2cf5462d17dac07e349234e21b97/ConfigArgParse-1.7-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d3/bb/d10e531b297dd1d46f6b1fd11d018247af9f2d460037554bb7bb9011c6ac/configobj-5.0.8-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/67/0f/6e5b4879594cd1cbb6a2754d9230937be444f404cf07c360c07a10b36aac/contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/7b/4e/fa4896744259ee8602464ed2c7330b736cc4dd3fd92f63cd56828bf36707/cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/63/22/bc266b167111e70a2da940e78b78d22fea5b1ee32b512ed0789bd6cc2a9f/dash-2.17.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/00/9e/a29f726e84e531a36d56cff187e61d8c96d2cc253c5bcef9a7695acb7e6a/dash_core_components-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/75/65/1b16b853844ef59b2742a7de74a598f376ac0ab581f0dcc34db294e5c90e/dash_html_components-2.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/da/ce/43f77dc8e7bbad02a9f88d07bf794eaf68359df756a28bb9f2f78e255bb1/dash_table-5.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/7a/27/78d5cf9c7aba43f8341e78273ab776913d2d33beb581ec39b65e56a0db77/debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e5/b6/1ed2eb03989ae574584664985367ba70cd9cf8b32ee8cad0e8aaeac819f3/descartes-1.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c9/7a/cef76fd8438a42f96db64ddaa85280485a9c395e7df3db8158cfec1eee34/dill-0.3.8-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f5/e8/f6bd1eee09314e7e6dee49cbe2c5e22314ccdb38db16c9fc72d2fa80d054/docker_pycreds-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/7c/e9fcff7623954d86bdc17782036cbf715ecab1bec4847c008557affe1ca8/docstring_parser-0.16-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/81/44/8a15e45ffa96e6cf82956dd8d7af9e666357e16b0d93b253903475ee947f/docutils-0.16-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/62/45/c663da77e3799057e561432b74967f3348cc985a2bdab433a7b01106611c/dulwich-0.22.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/90/c7/f4abf09c6109c975e462c72ea4f9e2d72d78e20325dafb151c8e9789a31d/embreex-2.17.7.post4-cp310-cp310-manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/91/9a/d882fd7562208456236fb2e62b762bf16fbc9ecde842bb871f676ca0f7e1/everett-3.1.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/01/90/79fe92dd413a9cab314ef5c591b5aa9b9ba787ae4cadab75055b0ae00b33/exceptiongroup-1.2.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/80/03/6ea8b1b2a5ab40a7a60dc464d3daa7aa546e0a74d74a9f8ff551ea7905db/executing-2.0.1-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9c/b9/79691036d4a8f9857e74d1728b23f34f583b81350a27492edda58d5604e1/fastjsonschema-2.19.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1b/1b/84c63f592ecdfbb3d77d22a8d93c9b92791e4fa35677ad71a7d6449100f8/fire-0.6.0.tar.gz - - pypi: https://files.pythonhosted.org/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/67/09/e09ee013d9d6f2f006147e5fc2b4d807eb2931f4f890c2d4f711e10391d7/fonttools-4.51.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/cb/56/f4845ed78723a4eb8eb22bcfcb46e1157a462c78c0a5ed318c68c98f9a79/gdown-5.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fd/5b/8f0c4a5bb9fd491c277c21eff7ccae71b47d43c4446c9d0c6cff2fe8c2c4/gitdb-4.0.11-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e9/bd/cc3a402a6439c15c3d4294333e13042b915bbeab54edc457c723931fed3f/GitPython-3.1.43-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/47/82/5f51b0ac0e670aa6551f351c6c8a479149a36c413dd76db4b98d26dddbea/grpcio-1.63.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/53/71/d9bf12b11f608f0ad078fa962a9ab61a2cf28fa9739293a1e842656bc419/gsplat-1.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/94/00/94bf8573e7487b7c37f2b613fc381880d48ec2311f2e859b8a5817deb4df/h5py-3.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/78/d4/e5d7e4f2174f8a4d63c8897d79eb8fe2503f7ecc03282fee1fa2719c2704/httpcore-1.0.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/41/7b/ddacf6dcebb42466abd03f368782142baa82e08fc0c1f8eaa05b4bae87d5/httpx-0.27.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/a3/b6/39c7dad203d9984225f47e0aa39ac3ba3a47c77a02d0ef2a7be691855a06/imageio-2.34.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/2d/0a/679461c511447ffaf176567d5c496d1de27cbe34a87df6677d7171b2fbd4/importlib_metadata-7.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/53/9d/40d5207db523363d9b5698f33778c18b0d591e3fdb6e0116b894b2a2491c/ipykernel-6.29.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/71/1b/c7bbd3e03ee6f3580a8afbdf8d6fd38279da03bd5c4bc431907ea3246f9a/ipython-8.24.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/70/1a/7edeedb1c089d63ccd8bd5c0612334774e90cf9337de9fe6c82d90081791/ipywidgets-8.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9a/0c/8055b6e60e6b2795c1cee6058287c39f168466e5937d6437b58b6c7e77f7/jaxtyping-0.2.28-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/20/9f/bc63f0f0737ad7a60800bfd472a4836661adae21f9c2535f3957b1e54ceb/jedi-0.19.1-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8a/3c/4f8791ee53ab9eeb0b022205aa79387119a74cc9429582ce04098e6fc540/json5-0.9.25-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/12/f6/0232cc0c617e195f06f810534d00b74d2f348fe71b2118009ad8ad31f878/jsonpointer-2.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c8/2f/324fab4be6fe37fb7b521546e8a557e6cf08c1c1b3d0b4839a00f589d9ef/jsonschema-4.22.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ee/07/44bd408781594c4d0a027666ef27fab1e441b109dc3b76b4f836f8fd04fe/jsonschema_specifications-2023.12.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/83/df/0f5dd132200728a86190397e1ea87cd76244e42d39ec5e88efd25b2abd7e/jupyter-1.0.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/75/6d/d7b55b9c1ac802ab066b3e5015e90faab1fffbbd67a2af498ffc6cc81c97/jupyter_client-8.6.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c9/fb/108ecd1fe961941959ad0ee4e12ee7b8b1477247f30b1fdfd83ceaf017f0/jupyter_core-5.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/a5/94/059180ea70a9a326e1815176b2370da56376da347a796f8c4f0b830208ef/jupyter_events-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/07/e0/7bd7cff65594fd9936e2f9385701e44574fc7d721331ff676ce440b14100/jupyter_lsp-2.2.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/95/85/483b8e09a897d1bc2194646d30d4ce6ae166106e91ecbd11d6b6d9ccfc36/jupyter_server-2.13.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/72/c3/532326adbb2b76f709e3e582aeefd0a85bd7454599ff450d90dd9540f5ed/jupyterlab-4.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/2f/b9/ed4ecad7cf1863a64920dc4c19b0376628b5d6bd28d2ec1e00cbac4ba2fb/jupyterlab_server-2.27.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/24/da/db1cb0387a7e4086780aff137987ee924e953d7f91b2a870f994b9b1eeb8/jupyterlab_widgets-3.0.10-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6f/40/4ab1fdb57fced80ce5903f04ae1aed7c1d5939dda4fd0c0aa526c12fe28a/kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/83/60/d497a310bde3f01cb805196ac61b7ad6dc5dcf8dce66634dc34364b20b4f/lazy_loader-0.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/5e/9e/e7768a8e363fc6f0c978bb7a0aa7641f10d80be60000e788ef2f01d34a7c/lightning_utilities-0.11.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/61/8a/a0a71720da1c61fd6a55a1962ec1280cebc4552c319efe744c8aa99d28c5/lxml-5.2.1-cp310-cp310-manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/a9/6d/8b08b54435ee0b2b1d0d3b9a5e212cc42f4dce08cd6e2441b3b9d216471a/mapbox_earcut-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/fc/b3/0c0c994fe49cd661084f8d5dc06562af53818cc0abefaca35bdc894577c3/Markdown-3.6-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d6/07/061f97211f942101070a46fecd813a6b1bd83590ed7b07c473cabd707fe7/matplotlib-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/1a/26/583ff25923efd88c90733a0fad51890c04e3367663b55548d0c9ed0a658c/mediapy-1.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f0/74/c95adcdf032956d9ef6c89a9b8a5152bf73915f8c633f3e3d88d06bd699c/mistune-3.0.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d9/96/a1868dd8997d65732476dfc70fef44d046c1b4dbe36ec1481ab744d87775/msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/9b/5d/f25ac7d4fb77cbd53ddc6d05d833c6bf52b12770a44fa9a447eed470ca9a/msgpack_numpy-0.4.8-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/bc/f7/7ec7fddc92e50714ea3745631f79bd9c96424cb2702632521028e57d3a36/multiprocess-0.70.16-py310-none-any.whl - - pypi: https://files.pythonhosted.org/packages/66/e8/00517a23d3eeaed0513e718fbc94aab26eaa1758f5690fc8578839791c79/nbclient-0.10.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/b8/bb/bb5b6a515d1584aa2fd89965b11db6632e4bdc69495a52374bcc36e56cfa/nbconvert-7.16.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f4/16/e93ebb619a3edd8851df21425fe20b7491bd1d819fc19beb9bfc1bf2556e/nerfacc-0.5.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6d/92/8d7aebd4430ab5ff65df2bfee6d5745f95c004284db2d8ca76dcbfd9de47/ninja-1.11.1.1-py2.py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/1a/e6/6d2ead760a9ddb35e65740fd5a57e46aadd7b0c49861ab24f94812797a1c/nodeenv-1.8.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f2/57/2f8d59ddc7f2d0d8ac4f80f869545bc44646fc78c1c083b3655c58e3edfb/notebook-7.0.7-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c6/53/460bf754677b3b247fb99a447e3575490dbc5f42ec94d528bc0137176f6a/nuscenes_devkit-1.1.9-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3b/e1/fc609763d982c6c43ee9503279fa6dc42d048b6224a9dc0a0ce8ac19308a/open3d-0.18.0-cp310-cp310-manylinux_2_27_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/f5/d0/2e455d894ec0d6527e662ad55e70c04f421ad83a6fd0a54c3dd73c411282/opencv_python-4.8.0.76-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/89/1b/12521efcbc6058e2673583bb096c2b5046a9df39bd73eca392c1efed24e5/pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f4/7f/cea34872c000d17972dad998575d14656d7c6bcf1a08a8d66d73c1ef2cca/pathos-0.3.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/b0/15/1691fa5aaddc0c4ea4901c26f6137c29d5f6673596fe960a0340e8c308e1/platformdirs-4.2.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/0b/f8/b65cdd2be32e442c4efe7b672f73c90b05eab5a7f3f4115efe181d432c60/plotly-5.22.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e1/d7/9e73c32f73da71e8224b4cb861b5db50ebdebcdff14d3e3fb47a63c578b2/pox-0.3.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ff/fa/5160c7d2fb1d4f2b83cba7a40f0eb4b015b78f6973b7ab6b2e73c233cfdc/ppft-1.7.6.8-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6d/8e/2df7467a15eae40e26c476683962fdb810cd1b36676603e2f139b4abbeaf/pretty_errors-1.2.25-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c7/98/745b810d822103adca2df8decd4c0bbe839ba7ad3511af3f0d09692fc0f0/prometheus_client-0.20.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ee/fd/ca7bf3869e7caa7a037e23078539467b433a4e01eebd93f77180ab927766/prompt_toolkit-3.0.43-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/31/be/80a9c6f16dfa4d41be3edbe655349778ae30882407fa8275eb46b4d34854/protobuf-3.20.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/c5/4f/0e22aaa246f96d6ac87fe5ebb9c5a693fbe8877f537a1022527c47ca43c5/psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/2b/27/77f9d5684e6bce929f5cfe18d6cfbe5133013c06cb2fbf5933670e60761d/pure_eval-0.2.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/23/7e/5f50d07d5e70a2addbccd90ac2950f81d1edd0783630651d9268d7f1db49/pyasn1-0.6.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ba/64/0451cf41a00fd5ac4501de4ea0e395b7d909e09d665e56890b5d3809ae26/pycocotools-2.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/dc/f1/5e81108414287278a01f1642271d7885e2aebc2bd10e7cf744d8c4cf0955/pycollada-0.8.tar.gz - - pypi: https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/2c/ba/a4bc465d36f6aafbff89da1bf67bcc6a97475b1d2300a74a778dcb293cef/pyliblzfse-0.4.1.tar.gz - - pypi: https://files.pythonhosted.org/packages/44/b2/5e98847b924748ec293bac6a68bb7d203a9ec328dbf7ef9fb886fd0e2c07/pymeshlab-2022.2.post3-cp310-cp310-manylinux1_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/cb/55/68b89d526e8331724665dcded0a32a76d73d6bcac41cc56084fda8e25486/pyngrok-7.1.6-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9d/ea/6d76df31432a0e6fdf81681a895f009a4bb47b3c39036db3e1b528191d52/pyparsing-3.1.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/49/b3/d8482e8cacc8ea15a356efea13d22ce1c5914a9ee36622ba250523240bf2/pyquaternion-0.9.9-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6f/32/3c865e7d62e481c46abffef3303db0d27bf2ca72e4f497d05d66939bfd4a/python_box-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/fe/e5/03fa8e76c718e1dd7fb5b74e9ce816ae0e08734080b1e98dbafbcf2fc8ba/python_engineio-4.9.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/af/bf/be12875b17709b591d8505811e513a88b31316e4ce0e801da351b4765ea5/python_socketio-5.11.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e2/8c/856047f955acc30179e9255fdc488059ca22f0938519523d53494f7cfee8/pytorch_msssim-1.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9c/3d/a121f284241f08268b21359bd425f7d4825cffc5ac5cd0e1b3d82ffd2b10/pytz-2024.1-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/40/4f/088d0fe18b188a0754483b7d632a97ef608dce80c2648219d071c9f1715c/pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/f2/3f/de5e5eb44900c1ed1c1567bc505e3b6e6f4c01cf29e558bf2f8cee29af5b/qtconsole-5.5.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/7e/a9/2146d5117ad8a81185331e0809a6b48933c10171f5bac253c6df9fce991c/QtPy-2.4.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/72/2f/80c24a0f24c3a8ae2a9b8cfb579bba0ddcdef9bfd420b98ce69a51b754d2/rawpy-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/b7/59/2056f61236782a2c86b33906c025d4f4a0b17be0161b63b70fd9e8775d36/referencing-0.35.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8f/04/9e36f28be4c0532c0e9207ff9dc01fb13a2b0eb036476a213b0000837d0e/retrying-1.3.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/87/67/a37f6214d0e9fe57f6ae54b2956d550ca8365857f42a1ce0392bb21d9410/rich-13.7.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e5/20/10c12b1acb102c4981a7e1dc86b60e36c1d5c940a7bda48643542f80dbff/rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/e9/93/0c0f002031f18b53af7a6166103c02b9c0667be528944137cc954ec921b3/rsa-4.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/59/a5/176d27468a1b0bcd7fa9c011cadacfa364e9bca8fa649baab7fb3f15af70/Rtree-1.2.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/83/37/395cdb6ee92925fa211e55d8f07b9f93cf93f60d7d4ce5e66fd73f1ea986/s3transfer-0.10.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/ea/82/264b5d0f2f4c4ec073e59dd1ac1ed5fa85f54bec2dd4cc231fcdfd12ba42/scikit_image-0.23.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/8f/38/420ee614359d8f453ffe2bb5c2e963bf50459d9bbd3f5a92aa9059658955/scikit_learn-1.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/b9/9d/39dbcf49a793157f9d4f5b8961855677eb4dbb4b82700dcee7042ad2310c/scipy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/6a/23/8146aad7d88f4fcb3a6218f41a60f6c2d4e3a72de72da1825dc7c8f7877c/semantic_version-2.10.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/cf/58/cfbed3fdc41891e9d2b45a5dbe706dcaf35429eb1446e30a504bb2ea9ea2/sentry_sdk-2.1.1-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/79/e7/54b36be02aee8ad573be68f6f46fd62838735c2f007b22df50eb5e13a20d/setproctitle-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/81/77/e1475695606a8305c9ad5f5132d911abe8ed1655a6f5c817a69bdd2b5324/shapely-2.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/e2/d1/a1d3189e7873408b9dc396aef0d7926c198b0df2aa3ddb5b539d3e89a70f/shtab-1.7.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6d/ea/288a8ac1d9551354488ff60c0ac6a76acc3b6b60f0460ac1944c75e240da/simple_websocket-1.0.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/cb/b6/ed513a0adc3e2c9654864ffb68266dcab5720d5653428d690e7e4fb32a6c/simplejson-3.19.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/a7/a5/10f97f73544edcdef54409f1d839f6049a0d79df68adbc1ceb24d1aaca42/smmap-5.0.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4c/f3/038b302fdfbe3be7da016777069f26ceefe11a681055ea1f7817546508e3/soupsieve-2.5-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/cd/a4/518bee82ace2681327e471f8f59e9958760a564775a8f650489da61205d3/splines-0.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d6/ea/ec6101e1710ac74e88b10312e9b59734885155e47d7dbb1171e4d347a364/svg.path-6.3-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/61/a1/6bb0cbebefb23641f068bb58a2bc56da9beb2b1c550242e3c540b37698f3/tenacity-8.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/3a/d0/b97889ffa769e2d1fdebb632084d5e8b53fc299d43a537acee7ec0c021a3/tensorboard-2.16.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/7a/13/e503968fefabd4c6b2650af21e110aa8466fe21432cd7c43a84577a89438/tensorboard_data_server-0.7.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d9/5f/8c716e47b3a50cbd7c146f45881e11d9414def768b7cd9c5e6650ec2a80a/termcolor-2.4.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/4b/2c/ffbf7a134b9ab11a67b0cf0726453cedd9c5043a4fe7a35d1cefa9a1bcfb/threadpoolctl-3.5.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c1/cf/dd1cdf85db58c811816377afd6ba8a240f4611e16f4085201598fb2d5578/tifffile-2024.5.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/72/ed/358a8bc5685c31c0fe7765351b202cf6a8c087893b5d2d64f63c950f8beb/timm-0.6.7-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/2c/4d/0db5b8a613d2a59bbc29bc5bb44a2f8070eb9ceab11c50d477502a8a0092/tinycss2-1.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9f/2c/e24c7e261eaa00fc911c39a5e30f77efbace480aae2548db9ceaef410945/torch_fidelity-0.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/aa/d9/b235d32de0f496492b108db7aea0cda42c58b713e2547a149385f1dfc8e3/torchmetrics-1.4.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9f/12/11d0a757bb67278d3380d41955ae98527d5ad18330b2edbdc8de222b569b/tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/18/eb/fdb7eb9e48b7b02554e1664afd3bd3f117f6b6d6c5881438a0b055554f9b/tqdm-4.66.4-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/57/7b/557a411622ff3e144d52bebbf8ad8a28bb18ee55ff68e1eb5ebfce755975/trimesh-4.3.2-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9a/bb/d43e5c75054e53efce310e79d63df0ac3f25e34c926be5dffb7d283fb2a8/typeguard-2.13.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c7/1b/af4f4c4f3f7339a4b7eb3c0ab13416db98f8ac09de3399129ee5fdfa282b/types_python_dateutil-2.9.0.20240316-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/8a/f6/0b3dca524fdba07dff7b1a029e5546212440e7d2ebd60fc5fc3f4c5d0fbc/tyro-0.8.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/7e/af/d3af73e45f8f2d1f3134df23f3832f2b248efadbc4a75d2de2fced454a20/vhacdx-0.0.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/e4/3a/c25edb89550c45e3456be6f266eda2850aa0d5226aab012cbfefc3a4decd/viser-0.1.27-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/b6/49/fd266df341165c7ed94f0e9875bb20cc75a59b1dd9b6f6a51a31db5f8527/wandb-0.17.0-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/d5/e1/3e9013159b4cbb71df9bd7611cbf90dc2c621c8aeeb677fc41dad72f2261/webcolors-1.13-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/67/b4/91683d7d5f66393e8877492fe4763304f82dbe308658a8db98f7a9e20baf/websocket_client-1.3.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/9a/12/c7a7504f5bf74d6ee0533f6fc7d30d8f4b79420ab179d1df2484b07602eb/websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/9d/6e/e792999e816d19d7fcbfa94c730936750036d65656a76a5a688b57a656c4/werkzeug-3.0.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/99/bc/82a8c3985209ca7c0a61b383c80e015fd92e74f8ba0ec1af98f9d6ca8dce/widgetsnbextension-4.0.10-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/49/83/b40bc1ad04a868b5b5bcec86349f06c1ee1ea7afe51dc3e46131e4f39308/wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/51/23/33f2ed4247e30770d964e3952bf4cbe13d22846eca940557447e0a4a2125/wurlitzer-3.1.0-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/29/ee/086c7cb4f067238e55fd645188232d67afe1ac6adacbea7a8cf2c6346cd8/xatlas-0.0.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/80/8a/1dd41557883b6196f8f092011a5c1f72d4d44cf36d7b67d4a5efe3127949/xxhash-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - - pypi: https://files.pythonhosted.org/packages/a5/a3/b182c56518f208e3b10a979a24dbe7348fc39edf19e6271b6cf5f8988c96/yourdfpy-0.0.56-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/c2/0a/ba9d0ee9536d3ef73a3448e931776e658b36f128d344e175bc32b092a8bf/zipp-3.18.1-py3-none-any.whl - - pypi: . -packages: -- kind: conda - name: _libgcc_mutex - version: '0.1' - build: conda_forge - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2 - sha256: fe51de6107f9edc7aa4f786a70f4a883943bc9d39b3bb7307c04c41410990726 - md5: d7c89558ba9fa0495403155b64376d81 - license: None - size: 2562 - timestamp: 1578324546067 -- kind: conda - name: _openmp_mutex - version: '4.5' - build: 2_kmp_llvm - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_kmp_llvm.tar.bz2 - sha256: 84a66275da3a66e3f3e70e9d8f10496d807d01a9e4ec16cd2274cc5e28c478fc - md5: 562b26ba2e19059551a811e72ab7f793 - depends: - - _libgcc_mutex 0.1 conda_forge - - llvm-openmp >=9.0.1 - license: BSD-3-Clause - license_family: BSD - size: 5744 - timestamp: 1650742457817 -- kind: pypi - name: absl-py - version: 2.1.0 - url: https://files.pythonhosted.org/packages/a2/ad/e0d3c824784ff121c03cc031f944bc7e139a8f1870ffd2845cc2dd76f6c4/absl_py-2.1.0-py3-none-any.whl - sha256: 526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308 - requires_python: '>=3.7' -- kind: pypi - name: addict - version: 2.4.0 - url: https://files.pythonhosted.org/packages/6a/00/b08f23b7d7e1e14ce01419a467b583edbb93c6cdb8654e54a9cc579cd61f/addict-2.4.0-py3-none-any.whl - sha256: 249bb56bbfd3cdc2a004ea0ff4c2b6ddc84d53bc2194761636eb314d5cfa5dfc -- kind: conda - name: alsa-lib - version: 1.2.11 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/alsa-lib-1.2.11-hd590300_1.conda - sha256: 0e2b75b9834a6e520b13db516f7cf5c9cea8f0bbc9157c978444173dacb98fec - md5: 0bb492cca54017ea314b809b1ee3a176 - depends: - - libgcc-ng >=12 - license: LGPL-2.1-or-later - license_family: GPL - size: 554699 - timestamp: 1709396557528 -- kind: pypi - name: anyio - version: 4.3.0 - url: https://files.pythonhosted.org/packages/14/fd/2f20c40b45e4fb4324834aea24bd4afdf1143390242c0b33774da0e2e34f/anyio-4.3.0-py3-none-any.whl - sha256: 048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8 - requires_dist: - - idna >=2.8 - - sniffio >=1.1 - - exceptiongroup >=1.0.2 ; python_version < '3.11' - - typing-extensions >=4.1 ; python_version < '3.11' - - packaging ; extra == 'doc' - - sphinx >=7 ; extra == 'doc' - - sphinx-rtd-theme ; extra == 'doc' - - sphinx-autodoc-typehints >=1.2.0 ; extra == 'doc' - - anyio[trio] ; extra == 'test' - - coverage[toml] >=7 ; extra == 'test' - - exceptiongroup >=1.2.0 ; extra == 'test' - - hypothesis >=4.0 ; extra == 'test' - - psutil >=5.9 ; extra == 'test' - - pytest >=7.0 ; extra == 'test' - - pytest-mock >=3.6.1 ; extra == 'test' - - trustme ; extra == 'test' - - uvloop >=0.17 ; (platform_python_implementation == 'CPython' and platform_system != 'Windows') and extra == 'test' - - trio >=0.23 ; extra == 'trio' - requires_python: '>=3.8' -- kind: conda - name: aom - version: 3.9.0 - build: hac33072_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.0-hac33072_0.conda - sha256: eef9b630ec0d3a3835c388b00685002d67d1d44db2af6c734921bdf65035654f - md5: 93a3bf248e5bc729807db198a9c89f07 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: BSD-2-Clause - license_family: BSD - size: 2701135 - timestamp: 1713925435201 -- kind: pypi - name: appdirs - version: 1.4.4 - url: https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl - sha256: a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128 -- kind: pypi - name: argon2-cffi - version: 23.1.0 - url: https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl - sha256: c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea - requires_dist: - - argon2-cffi-bindings - - typing-extensions ; python_version < '3.8' - - argon2-cffi[tests,typing] ; extra == 'dev' - - tox >4 ; extra == 'dev' - - furo ; extra == 'docs' - - myst-parser ; extra == 'docs' - - sphinx ; extra == 'docs' - - sphinx-copybutton ; extra == 'docs' - - sphinx-notfound-page ; extra == 'docs' - - hypothesis ; extra == 'tests' - - pytest ; extra == 'tests' - - mypy ; extra == 'typing' - requires_python: '>=3.7' -- kind: pypi - name: argon2-cffi-bindings - version: 21.2.0 - url: https://files.pythonhosted.org/packages/ec/f7/378254e6dd7ae6f31fe40c8649eea7d4832a42243acaf0f1fff9083b2bed/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae - requires_dist: - - cffi >=1.0.1 - - pytest ; extra == 'dev' - - cogapp ; extra == 'dev' - - pre-commit ; extra == 'dev' - - wheel ; extra == 'dev' - - pytest ; extra == 'tests' - requires_python: '>=3.6' -- kind: pypi - name: arrow - version: 1.3.0 - url: https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl - sha256: c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80 - requires_dist: - - python-dateutil >=2.7.0 - - types-python-dateutil >=2.8.10 - - doc8 ; extra == 'doc' - - sphinx >=7.0.0 ; extra == 'doc' - - sphinx-autobuild ; extra == 'doc' - - sphinx-autodoc-typehints ; extra == 'doc' - - sphinx-rtd-theme >=1.3.0 ; extra == 'doc' - - dateparser ==1.* ; extra == 'test' - - pre-commit ; extra == 'test' - - pytest ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-mock ; extra == 'test' - - pytz ==2021.1 ; extra == 'test' - - simplejson ==3.* ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: asttokens - version: 2.4.1 - url: https://files.pythonhosted.org/packages/45/86/4736ac618d82a20d87d2f92ae19441ebc7ac9e7a581d7e58bbe79233b24a/asttokens-2.4.1-py2.py3-none-any.whl - sha256: 051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24 - requires_dist: - - six >=1.12.0 - - typing ; python_version < '3.5' - - astroid <2, >=1 ; python_version < '3' and extra == 'astroid' - - astroid <4, >=2 ; python_version >= '3' and extra == 'astroid' - - pytest ; extra == 'test' - - astroid <2, >=1 ; python_version < '3' and extra == 'test' - - astroid <4, >=2 ; python_version >= '3' and extra == 'test' -- kind: pypi - name: async-lru - version: 2.0.4 - url: https://files.pythonhosted.org/packages/fa/9f/3c3503693386c4b0f245eaf5ca6198e3b28879ca0a40bde6b0e319793453/async_lru-2.0.4-py3-none-any.whl - sha256: ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224 - requires_dist: - - typing-extensions >=4.0.0 ; python_version < '3.11' - requires_python: '>=3.8' -- kind: conda - name: attr - version: 2.5.1 - build: h166bdaf_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.1-h166bdaf_1.tar.bz2 - sha256: 82c13b1772c21fc4a17441734de471d3aabf82b61db9b11f4a1bd04a9c4ac324 - md5: d9c69a24ad678ffce24c6543a0176b00 - depends: - - libgcc-ng >=12 - license: GPL-2.0-or-later - license_family: GPL - size: 71042 - timestamp: 1660065501192 -- kind: pypi - name: attrs - version: 23.2.0 - url: https://files.pythonhosted.org/packages/e0/44/827b2a91a5816512fcaf3cc4ebc465ccd5d598c45cefa6703fcf4a79018f/attrs-23.2.0-py3-none-any.whl - sha256: 99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1 - requires_dist: - - importlib-metadata ; python_version < '3.8' - - attrs[tests] ; extra == 'cov' - - coverage[toml] >=5.3 ; extra == 'cov' - - attrs[tests] ; extra == 'dev' - - pre-commit ; extra == 'dev' - - furo ; extra == 'docs' - - myst-parser ; extra == 'docs' - - sphinx ; extra == 'docs' - - sphinx-notfound-page ; extra == 'docs' - - sphinxcontrib-towncrier ; extra == 'docs' - - towncrier ; extra == 'docs' - - zope-interface ; extra == 'docs' - - attrs[tests-no-zope] ; extra == 'tests' - - zope-interface ; extra == 'tests' - - mypy >=1.6 ; (platform_python_implementation == 'CPython' and python_version >= '3.8') and extra == 'tests-mypy' - - pytest-mypy-plugins ; (platform_python_implementation == 'CPython' and python_version >= '3.8') and extra == 'tests-mypy' - - attrs[tests-mypy] ; extra == 'tests-no-zope' - - cloudpickle ; platform_python_implementation == 'CPython' and extra == 'tests-no-zope' - - hypothesis ; extra == 'tests-no-zope' - - pympler ; extra == 'tests-no-zope' - - pytest-xdist[psutil] ; extra == 'tests-no-zope' - - pytest >=4.3.0 ; extra == 'tests-no-zope' - requires_python: '>=3.7' -- kind: pypi - name: av - version: 12.0.0 - url: https://files.pythonhosted.org/packages/50/c3/81e9efb59751b7a151c213f7976ce3bfac9a7786949947afbd60eee279df/av-12.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 39f0b4cfb89f4f06b339c766f92648e798a96747d4163f2fa78660d1ab1f1b5e - requires_python: '>=3.8' -- kind: conda - name: aws-c-auth - version: 0.7.18 - build: he0b1f16_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.7.18-he0b1f16_0.conda - sha256: 03dbdc7a3bb8a92d5404fcfc2ff2a68037860bb8a54dae345384b54f206c638f - md5: 5f4ec63692861f4a812898a4fbd5cc20 - depends: - - aws-c-cal >=0.6.11,<0.6.12.0a0 - - aws-c-common >=0.9.15,<0.9.16.0a0 - - aws-c-http >=0.8.1,<0.8.2.0a0 - - aws-c-io >=0.14.7,<0.14.8.0a0 - - aws-c-sdkutils >=0.1.15,<0.1.16.0a0 - - libgcc-ng >=12 - license: Apache-2.0 - license_family: Apache - size: 104635 - timestamp: 1713478222324 -- kind: conda - name: aws-c-cal - version: 0.6.11 - build: heb1d5e4_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.6.11-heb1d5e4_0.conda - sha256: f1b40106a70cc294aab350daa97c760a9875073f58a5b7a25370c31fed8a2c15 - md5: 98784bb35b316e2ba8698f4a75326e9a - depends: - - aws-c-common >=0.9.15,<0.9.16.0a0 - - libgcc-ng >=12 - - openssl >=3.2.1,<4.0a0 - license: Apache-2.0 - license_family: Apache - size: 46257 - timestamp: 1712494861919 -- kind: conda - name: aws-c-common - version: 0.9.15 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.9.15-hd590300_0.conda - sha256: e4251e5fa2656140628f40b74e61cf5048dfd4346f6d81517d346b371113496e - md5: ad8955a300fd09e97e76c38638ac7157 - depends: - - libgcc-ng >=12 - license: Apache-2.0 - license_family: Apache - size: 226559 - timestamp: 1712101677803 -- kind: conda - name: aws-c-compression - version: 0.2.18 - build: hce8ee76_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.2.18-hce8ee76_3.conda - sha256: ab0617f2d66d5d88fc6c7edb6ecd4589e0a744ccaeff95765371c9cabdb29722 - md5: b19224a5179ecb512c4aac9f8a6d57a7 - depends: - - aws-c-common >=0.9.15,<0.9.16.0a0 - - libgcc-ng >=12 - license: Apache-2.0 - license_family: Apache - size: 19134 - timestamp: 1712138634166 -- kind: conda - name: aws-c-event-stream - version: 0.4.2 - build: h01f5eca_8 - build_number: 8 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.4.2-h01f5eca_8.conda - sha256: 688b81ed93151868df2717556d3b93dcfaf6bf129a1474f14e0c993095816d3f - md5: afb85fc0f01032d115c57c961950e7d8 - depends: - - aws-c-common >=0.9.15,<0.9.16.0a0 - - aws-c-io >=0.14.7,<0.14.8.0a0 - - aws-checksums >=0.1.18,<0.1.19.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: Apache-2.0 - license_family: Apache - size: 53700 - timestamp: 1712507243610 -- kind: conda - name: aws-c-http - version: 0.8.1 - build: hdb68c23_10 - build_number: 10 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.8.1-hdb68c23_10.conda - sha256: a13e77f6b40de79b33711f70b8180943053cc162efdb357bc9cd577f0ac69818 - md5: cb6065938167da2d2f078c2f08473b84 - depends: - - aws-c-cal >=0.6.11,<0.6.12.0a0 - - aws-c-common >=0.9.15,<0.9.16.0a0 - - aws-c-compression >=0.2.18,<0.2.19.0a0 - - aws-c-io >=0.14.7,<0.14.8.0a0 - - libgcc-ng >=12 - license: Apache-2.0 - license_family: Apache - size: 195362 - timestamp: 1712654535499 -- kind: conda - name: aws-c-io - version: 0.14.7 - build: hbfbeace_6 - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.14.7-hbfbeace_6.conda - sha256: 10c8df9b71be8aba9b1aad48b123fc81896eb7b73c686042bed4a9e77d92e812 - md5: d6382461de9a91a2665e964f92d8da0a - depends: - - aws-c-cal >=0.6.11,<0.6.12.0a0 - - aws-c-common >=0.9.15,<0.9.16.0a0 - - libgcc-ng >=12 - - s2n >=1.4.12,<1.4.13.0a0 - license: Apache-2.0 - license_family: Apache - size: 158124 - timestamp: 1713346977725 -- kind: conda - name: aws-c-mqtt - version: 0.10.4 - build: h50844eb_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.10.4-h50844eb_0.conda - sha256: a6588943583636337ab4fb6233df7b8fc5e42199dafc415d5b8a968a7ff11a8f - md5: 3d3a35463e550d2e098cede57b3977b1 - depends: - - aws-c-common >=0.9.15,<0.9.16.0a0 - - aws-c-http >=0.8.1,<0.8.2.0a0 - - aws-c-io >=0.14.7,<0.14.8.0a0 - - libgcc-ng >=12 - license: Apache-2.0 - license_family: Apache - size: 163389 - timestamp: 1714086029743 -- kind: conda - name: aws-c-s3 - version: 0.5.7 - build: h6be9164_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.5.7-h6be9164_2.conda - sha256: 5a7c84e3be0dc041fc537a6c5dc9a63a4d7ed535d05bba8a5d49666bc022df89 - md5: 88b24a3a618acd279502f5960442c8a2 - depends: - - aws-c-auth >=0.7.18,<0.7.19.0a0 - - aws-c-cal >=0.6.11,<0.6.12.0a0 - - aws-c-common >=0.9.15,<0.9.16.0a0 - - aws-c-http >=0.8.1,<0.8.2.0a0 - - aws-c-io >=0.14.7,<0.14.8.0a0 - - aws-checksums >=0.1.18,<0.1.19.0a0 - - libgcc-ng >=12 - - openssl >=3.2.1,<4.0a0 - license: Apache-2.0 - license_family: Apache - size: 107839 - timestamp: 1713520889154 -- kind: conda - name: aws-c-sdkutils - version: 0.1.15 - build: hce8ee76_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.1.15-hce8ee76_3.conda - sha256: 72fd73a5de0730997a36bf20ac1cb8cf7c67e40225c280b3dc5e46bc61c7d157 - md5: 0c4f0205a1ae4ca6c89af922ec54271c - depends: - - aws-c-common >=0.9.15,<0.9.16.0a0 - - libgcc-ng >=12 - license: Apache-2.0 - license_family: Apache - size: 55146 - timestamp: 1712145768196 -- kind: conda - name: aws-checksums - version: 0.1.18 - build: hce8ee76_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.1.18-hce8ee76_3.conda - sha256: de0ba47fc8feaaa087d9128e4b5402af72bd46af52b885dee87adfb9e285a816 - md5: 9aa734a17b9b0b793c7696435fe7789a - depends: - - aws-c-common >=0.9.15,<0.9.16.0a0 - - libgcc-ng >=12 - license: Apache-2.0 - license_family: Apache - size: 50068 - timestamp: 1712145648515 -- kind: conda - name: aws-crt-cpp - version: 0.26.8 - build: h2150271_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.26.8-h2150271_2.conda - sha256: 61feed2a595c6ceedbebea5150c3b4298fb13a742793e0f2506ef995288a5f27 - md5: 9ee890489734098ce5b3d435b7ec4b80 - depends: - - aws-c-auth >=0.7.18,<0.7.19.0a0 - - aws-c-cal >=0.6.11,<0.6.12.0a0 - - aws-c-common >=0.9.15,<0.9.16.0a0 - - aws-c-event-stream >=0.4.2,<0.4.3.0a0 - - aws-c-http >=0.8.1,<0.8.2.0a0 - - aws-c-io >=0.14.7,<0.14.8.0a0 - - aws-c-mqtt >=0.10.4,<0.10.5.0a0 - - aws-c-s3 >=0.5.7,<0.5.8.0a0 - - aws-c-sdkutils >=0.1.15,<0.1.16.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: Apache-2.0 - license_family: Apache - size: 340265 - timestamp: 1714132568550 -- kind: conda - name: aws-sdk-cpp - version: 1.11.267 - build: hddb5a97_7 - build_number: 7 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.267-hddb5a97_7.conda - sha256: 1940f4e1e01ae8232092c07d3919496832b36be8ca9f50279b0086b0b5028639 - md5: c6a0616fb788d14efb45ecca46f2f358 - depends: - - aws-c-common >=0.9.15,<0.9.16.0a0 - - aws-c-event-stream >=0.4.2,<0.4.3.0a0 - - aws-checksums >=0.1.18,<0.1.19.0a0 - - aws-crt-cpp >=0.26.8,<0.26.9.0a0 - - libcurl >=8.7.1,<9.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - openssl >=3.2.1,<4.0a0 - license: Apache-2.0 - license_family: Apache - size: 3638454 - timestamp: 1713967770190 -- kind: pypi - name: awscli - version: 1.32.100 - url: https://files.pythonhosted.org/packages/14/cc/e0cce71e334a1fc4665a52bdb9b88c95952251643eb4382ad8a8954831ec/awscli-1.32.100-py3-none-any.whl - sha256: 46e4a44dafeffe63980ab2cd0240aa15a4879cf5d84f210c9eb0facc05e7bf0a - requires_dist: - - botocore ==1.34.100 - - docutils <0.17, >=0.10 - - s3transfer <0.11.0, >=0.10.0 - - pyyaml <6.1, >=3.10 - - colorama <0.4.7, >=0.2.5 - - rsa <4.8, >=3.1.2 - requires_python: '>=3.8' -- kind: pypi - name: babel - version: 2.15.0 - url: https://files.pythonhosted.org/packages/27/45/377f7e32a5c93d94cd56542349b34efab5ca3f9e2fd5a68c5e93169aa32d/Babel-2.15.0-py3-none-any.whl - sha256: 08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb - requires_dist: - - pytz >=2015.7 ; python_version < '3.9' - - pytest >=6.0 ; extra == 'dev' - - pytest-cov ; extra == 'dev' - - freezegun ~=1.0 ; extra == 'dev' - requires_python: '>=3.8' -- kind: pypi - name: beautifulsoup4 - version: 4.12.3 - url: https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl - sha256: b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed - requires_dist: - - soupsieve >1.2 - - cchardet ; extra == 'cchardet' - - chardet ; extra == 'chardet' - - charset-normalizer ; extra == 'charset-normalizer' - - html5lib ; extra == 'html5lib' - - lxml ; extra == 'lxml' - requires_python: '>=3.6.0' -- kind: pypi - name: bidict - version: 0.23.1 - url: https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl - sha256: 5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5 - requires_python: '>=3.8' -- kind: conda - name: blas - version: '1.0' - build: mkl - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/blas-1.0-mkl.tar.bz2 - sha256: a9a9125029a66905fc9e932dfd4f595be3a59a30db37fd7bf4a675a5c6151d62 - md5: 349aef876b1d8c9dccae01de20d5b385 - depends: - - mkl - track_features: - - blas_mkl - license: BSD 3-clause - size: 1381 -- kind: pypi - name: bleach - version: 6.1.0 - url: https://files.pythonhosted.org/packages/ea/63/da7237f805089ecc28a3f36bca6a21c31fcbc2eb380f3b8f1be3312abd14/bleach-6.1.0-py3-none-any.whl - sha256: 3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6 - requires_dist: - - six >=1.9.0 - - webencodings - - tinycss2 <1.3, >=1.1.0 ; extra == 'css' - requires_python: '>=3.8' -- kind: pypi - name: blinker - version: 1.8.2 - url: https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl - sha256: 1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01 - requires_python: '>=3.8' -- kind: pypi - name: botocore - version: 1.34.100 - url: https://files.pythonhosted.org/packages/d3/4d/86d46c869bd32c46bce4290a6dac45ff63e92fbc034c67ccb35b6477caab/botocore-1.34.100-py3-none-any.whl - sha256: ee516fb9e9e906d311f2a9921afaf79c594db239a5b4b626e89e6960401aad0b - requires_dist: - - jmespath <2.0.0, >=0.7.1 - - python-dateutil <3.0.0, >=2.1 - - urllib3 <1.27, >=1.25.4 ; python_version < '3.10' - - urllib3 !=2.2.0, <3, >=1.25.4 ; python_version >= '3.10' - - awscrt ==0.20.9 ; extra == 'crt' - requires_python: '>=3.8' -- kind: conda - name: brotli-python - version: 1.1.0 - build: py310hc6cd4ac_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.1.0-py310hc6cd4ac_1.conda - sha256: e22268d81905338570786921b3def88e55f9ed6d0ccdd17d9fbae31a02fbef69 - md5: 1f95722c94f00b69af69a066c7433714 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - python >=3.10,<3.11.0a0 - - python_abi 3.10.* *_cp310 - constrains: - - libbrotlicommon 1.1.0 hd590300_1 - license: MIT - license_family: MIT - purls: - - pkg:pypi/brotli - size: 349397 - timestamp: 1695990295884 -- kind: conda - name: bzip2 - version: 1.0.8 - build: hd590300_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hd590300_5.conda - sha256: 242c0c324507ee172c0e0dd2045814e746bb303d1eb78870d182ceb0abc726a8 - md5: 69b8b6202a07720f448be700e300ccf4 - depends: - - libgcc-ng >=12 - license: bzip2-1.0.6 - license_family: BSD - size: 254228 - timestamp: 1699279927352 -- kind: conda - name: c-ares - version: 1.28.1 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.28.1-hd590300_0.conda - sha256: cb25063f3342149c7924b21544109696197a9d774f1407567477d4f3026bf38a - md5: dcde58ff9a1f30b0037a2315d1846d1f - depends: - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 168875 - timestamp: 1711819445938 -- kind: conda - name: ca-certificates - version: 2024.2.2 - build: hbcca054_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2024.2.2-hbcca054_0.conda - sha256: 91d81bfecdbb142c15066df70cc952590ae8991670198f92c66b62019b251aeb - md5: 2f4327a1cbe7f022401b236e915a5fef - license: ISC - size: 155432 - timestamp: 1706843687645 -- kind: pypi - name: cachetools - version: 5.3.3 - url: https://files.pythonhosted.org/packages/fb/2b/a64c2d25a37aeb921fddb929111413049fc5f8b9a4c1aefaffaafe768d54/cachetools-5.3.3-py3-none-any.whl - sha256: 0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945 - requires_python: '>=3.7' -- kind: conda - name: cairo - version: 1.18.0 - build: h3faef2a_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.0-h3faef2a_0.conda - sha256: 142e2639a5bc0e99c44d76f4cc8dce9c6a2d87330c4beeabb128832cd871a86e - md5: f907bb958910dc404647326ca80c263e - depends: - - fontconfig >=2.14.2,<3.0a0 - - fonts-conda-ecosystem - - freetype >=2.12.1,<3.0a0 - - icu >=73.2,<74.0a0 - - libgcc-ng >=12 - - libglib >=2.78.0,<3.0a0 - - libpng >=1.6.39,<1.7.0a0 - - libstdcxx-ng >=12 - - libxcb >=1.15,<1.16.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - pixman >=0.42.2,<1.0a0 - - xorg-libice >=1.1.1,<2.0a0 - - xorg-libsm >=1.2.4,<2.0a0 - - xorg-libx11 >=1.8.6,<2.0a0 - - xorg-libxext >=1.3.4,<2.0a0 - - xorg-libxrender >=0.9.11,<0.10.0a0 - - zlib - license: LGPL-2.1-only or MPL-1.1 - size: 982351 - timestamp: 1697028423052 -- kind: conda - name: ceres-solver - version: 2.2.0 - build: h30ec75d_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ceres-solver-2.2.0-h30ec75d_2.conda - sha256: 8db7b51a75ab27410738b826d4803ae90e8fb445cd614c79129b7b4abfcaabd4 - md5: 3e22f317903149ec5220795a9bc32aad - depends: - - eigen - - gflags >=2.2.2,<2.3.0a0 - - glog >=0.7.0,<0.8.0a0 - - libblas >=3.9.0,<4.0a0 - - libcblas >=3.9.0,<4.0a0 - - libgcc-ng >=12 - - liblapack >=3.9.0,<4.0a0 - - libstdcxx-ng >=12 - - suitesparse >=5.10.1,<6.0a0 - - tbb - license: BSD-3-Clause - license_family: BSD - size: 1463615 - timestamp: 1708286440640 -- kind: conda - name: certifi - version: 2024.2.2 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/certifi-2024.2.2-pyhd8ed1ab_0.conda - sha256: f1faca020f988696e6b6ee47c82524c7806380b37cfdd1def32f92c326caca54 - md5: 0876280e409658fc6f9e75d035960333 - depends: - - python >=3.7 - license: ISC - purls: - - pkg:pypi/certifi - size: 160559 - timestamp: 1707022289175 -- kind: pypi - name: cffi - version: 1.16.0 - url: https://files.pythonhosted.org/packages/c9/7c/43d81bdd5a915923c3bad5bb4bff401ea00ccc8e28433fb6083d2e3bf58e/cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 - requires_dist: - - pycparser - requires_python: '>=3.8' -- kind: pypi - name: chardet - version: 5.2.0 - url: https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl - sha256: e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970 - requires_python: '>=3.7' -- kind: conda - name: charset-normalizer - version: 3.3.2 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.3.2-pyhd8ed1ab_0.conda - sha256: 20cae47d31fdd58d99c4d2e65fbdcefa0b0de0c84e455ba9d6356a4bdbc4b5b9 - md5: 7f4a9e3fcff3f6356ae99244a014da6a - depends: - - python >=3.7 - license: MIT - license_family: MIT - purls: - - pkg:pypi/charset-normalizer - size: 46597 - timestamp: 1698833765762 -- kind: pypi - name: click - version: 8.1.7 - url: https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl - sha256: ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 - requires_dist: - - colorama ; platform_system == 'Windows' - - importlib-metadata ; python_version < '3.8' - requires_python: '>=3.7' -- kind: conda - name: colmap - version: 3.9.1 - build: cpuhe398016_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/colmap-3.9.1-cpuhe398016_3.conda - sha256: 7affed44ed46eba539ab08b339a2cdf068044476eda544825ff169145b682a6d - md5: 5acfefed4bc8fa569fa198437817f18b - depends: - - __glibc >=2.17,<3.0.a0 - - _openmp_mutex >=4.5 - - ceres-solver >=2.2.0,<2.3.0a0 - - eigen >=3.4.0,<3.4.1.0a0 - - flann >=1.9.2,<1.9.3.0a0 - - freeimage >=3.18.0,<3.19.0a0 - - gflags >=2.2.2,<2.3.0a0 - - glew >=2.1.0,<2.2.0a0 - - glog >=0.7.0,<0.8.0a0 - - gmp >=6.3.0,<7.0a0 - - libblas >=3.9.0,<4.0a0 - - libboost >=1.84.0,<1.85.0a0 - - libcblas >=3.9.0,<4.0a0 - - libgcc-ng >=12 - - libglu - - libsqlite >=3.45.2,<4.0a0 - - libstdcxx-ng >=12 - - libxcb >=1.15,<1.16.0a0 - - lz4-c >=1.9.3,<1.10.0a0 - - metis >=5.1.0,<5.1.1.0a0 - - qt-main >=5.15.8,<5.16.0a0 - - suitesparse >=5.10.1,<6.0a0 - - vlfeat >=0.9.21,<0.9.22.0a0 - - xorg-libice >=1.1.1,<2.0a0 - - xorg-libsm >=1.2.4,<2.0a0 - - xorg-libx11 >=1.8.7,<2.0a0 - - xorg-libxau >=1.0.11,<2.0a0 - - xorg-libxdmcp - - xorg-libxext >=1.3.4,<2.0a0 - - xorg-libxfixes - - xorg-libxrender >=0.9.11,<0.10.0a0 - license: BSD-3-Clause - license_family: BSD - size: 6321163 - timestamp: 1711680295114 -- kind: pypi - name: colorama - version: 0.4.6 - url: https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl - sha256: 4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 - requires_python: '!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7' -- kind: pypi - name: colorlog - version: 6.8.2 - url: https://files.pythonhosted.org/packages/f3/18/3e867ab37a24fdf073c1617b9c7830e06ec270b1ea4694a624038fc40a03/colorlog-6.8.2-py3-none-any.whl - sha256: 4dcbb62368e2800cb3c5abd348da7e53f6c362dda502ec27c560b2e58a66bd33 - requires_dist: - - colorama ; sys_platform == 'win32' - - black ; extra == 'development' - - flake8 ; extra == 'development' - - mypy ; extra == 'development' - - pytest ; extra == 'development' - - types-colorama ; extra == 'development' - requires_python: '>=3.6' -- kind: pypi - name: comet-ml - version: 3.41.0 - url: https://files.pythonhosted.org/packages/67/38/34ca2481c857c704ce2c44a78df31eed98b05558c87be097a1eb430ec332/comet_ml-3.41.0-py3-none-any.whl - sha256: bdbb4ab0097567eed9d89a9e14372d7623993a64b330adc6c74a0ea9de379167 - requires_dist: - - everett[ini] <3.2.0, >=1.0.1 - - jsonschema !=3.1.0, >=2.6.0 - - psutil >=5.6.3 - - python-box <7.0.0 - - requests-toolbelt >=0.8.0 - - requests >=2.18.4 - - semantic-version >=2.8.0 - - sentry-sdk >=1.1.0 - - simplejson - - six - - urllib3 >=1.21.1 - - websocket-client <1.4.0, >=0.55.0 - - wrapt >=1.11.2 - - wurlitzer >=1.0.2 - - comet-git-pure >=0.19.11 ; python_version < '3.0' - - importlib-metadata ; python_version < '3.8' - - dulwich !=0.20.33, >=0.20.6 ; python_version >= '3.0' - - setuptools ; python_version >= '3.12' - - rich >=13.3.2 ; python_version >= '3.7.0' - requires_python: '>=3.6' -- kind: pypi - name: comm - version: 0.2.2 - url: https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl - sha256: e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3 - requires_dist: - - traitlets >=4 - - pytest ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: configargparse - version: '1.7' - url: https://files.pythonhosted.org/packages/6f/b3/b4ac838711fd74a2b4e6f746703cf9dd2cf5462d17dac07e349234e21b97/ConfigArgParse-1.7-py3-none-any.whl - sha256: d249da6591465c6c26df64a9f73d2536e743be2f244eb3ebe61114af2f94f86b - requires_dist: - - mock ; extra == 'test' - - pyyaml ; extra == 'test' - - pytest ; extra == 'test' - - pyyaml ; extra == 'yaml' - requires_python: '>=3.5' -- kind: pypi - name: configobj - version: 5.0.8 - url: https://files.pythonhosted.org/packages/d3/bb/d10e531b297dd1d46f6b1fd11d018247af9f2d460037554bb7bb9011c6ac/configobj-5.0.8-py2.py3-none-any.whl - sha256: a7a8c6ab7daade85c3f329931a807c8aee750a2494363934f8ea84d8a54c87ea - requires_dist: - - six - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' -- kind: pypi - name: contourpy - version: 1.2.1 - url: https://files.pythonhosted.org/packages/67/0f/6e5b4879594cd1cbb6a2754d9230937be444f404cf07c360c07a10b36aac/contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b - requires_dist: - - numpy >=1.20 - - furo ; extra == 'docs' - - sphinx >=7.2 ; extra == 'docs' - - sphinx-copybutton ; extra == 'docs' - - bokeh ; extra == 'bokeh' - - selenium ; extra == 'bokeh' - - contourpy[bokeh,docs] ; extra == 'mypy' - - docutils-stubs ; extra == 'mypy' - - mypy ==1.8.0 ; extra == 'mypy' - - types-pillow ; extra == 'mypy' - - contourpy[test-no-images] ; extra == 'test' - - matplotlib ; extra == 'test' - - pillow ; extra == 'test' - - pytest ; extra == 'test-no-images' - - pytest-cov ; extra == 'test-no-images' - - pytest-xdist ; extra == 'test-no-images' - - wurlitzer ; extra == 'test-no-images' - requires_python: '>=3.9' -- kind: pypi - name: cryptography - version: 42.0.7 - url: https://files.pythonhosted.org/packages/7b/4e/fa4896744259ee8602464ed2c7330b736cc4dd3fd92f63cd56828bf36707/cryptography-42.0.7-cp39-abi3-manylinux_2_28_x86_64.whl - sha256: efd0bf5205240182e0f13bcaea41be4fdf5c22c5129fc7ced4a0282ac86998c9 - requires_dist: - - cffi >=1.12 ; platform_python_implementation != 'PyPy' - - sphinx >=5.3.0 ; extra == 'docs' - - sphinx-rtd-theme >=1.1.1 ; extra == 'docs' - - pyenchant >=1.6.11 ; extra == 'docstest' - - readme-renderer ; extra == 'docstest' - - sphinxcontrib-spelling >=4.0.1 ; extra == 'docstest' - - nox ; extra == 'nox' - - ruff ; extra == 'pep8test' - - mypy ; extra == 'pep8test' - - check-sdist ; extra == 'pep8test' - - click ; extra == 'pep8test' - - build ; extra == 'sdist' - - bcrypt >=3.1.5 ; extra == 'ssh' - - pytest >=6.2.0 ; extra == 'test' - - pytest-benchmark ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-xdist ; extra == 'test' - - pretend ; extra == 'test' - - certifi ; extra == 'test' - - pytest-randomly ; extra == 'test-randomorder' - requires_python: '>=3.7' -- kind: conda - name: cuda - version: 11.8.0 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-11.8.0-0.tar.bz2 - md5: f274f527ae9d4393e93768c33d8e0058 - depends: - - cuda-demo-suite >=11.8.86 - - cuda-runtime >=11.8.0 - - cuda-toolkit >=11.8.0 - arch: x86_64 - platform: linux - size: 1449 - timestamp: 1664475582997 -- kind: conda - name: cuda-cccl - version: 11.8.89 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cccl-11.8.89-0.tar.bz2 - md5: 9c48a93deca9c86ab9393c717b55c89d - arch: x86_64 - platform: linux - size: 1232088 - timestamp: 1663786133781 -- kind: conda - name: cuda-command-line-tools - version: 11.8.0 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-command-line-tools-11.8.0-0.tar.bz2 - md5: b782d1e340ffbb8940633bf57e38ea91 - depends: - - cuda-cupti >=11.8.87 - - cuda-gdb >=11.8.86 - - cuda-memcheck >=11.8.86 - - cuda-nvdisasm >=11.8.86 - - cuda-nvprof >=11.8.87 - - cuda-nvtx >=11.8.86 - - cuda-sanitizer-api >=11.8.86 - arch: x86_64 - platform: linux - size: 1503 - timestamp: 1664475471680 -- kind: conda - name: cuda-compiler - version: 11.8.0 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-compiler-11.8.0-0.tar.bz2 - md5: 37f4f099ae0801d57c8547c0f3af6b8f - depends: - - cuda-cuobjdump >=11.8.86 - - cuda-cuxxfilt >=11.8.86 - - cuda-nvcc >=11.8.89 - - cuda-nvprune >=11.8.86 - arch: x86_64 - platform: linux - size: 1464 - timestamp: 1664475480949 -- kind: conda - name: cuda-cudart - version: 11.8.89 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cudart-11.8.89-0.tar.bz2 - md5: b68c7ef3eda01e95d5903fb508c5e440 - arch: x86_64 - platform: linux - size: 201959 - timestamp: 1663787236799 -- kind: conda - name: cuda-cudart-dev - version: 11.8.89 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cudart-dev-11.8.89-0.tar.bz2 - md5: fda2522594365c493121c517d3cc5a29 - depends: - - cuda-cccl - - cuda-cudart >=11.8.89 - arch: x86_64 - platform: linux - size: 1137073 - timestamp: 1663787238388 -- kind: conda - name: cuda-cuobjdump - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cuobjdump-11.8.86-0.tar.bz2 - md5: 9983898404071b86e93f5411e9ce73d5 - arch: x86_64 - platform: linux - size: 234042 - timestamp: 1661544389189 -- kind: conda - name: cuda-cupti - version: 11.8.87 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cupti-11.8.87-0.tar.bz2 - md5: 2f4b4933285400137cf029fef9a7daa6 - arch: x86_64 - platform: linux - size: 26508245 - timestamp: 1661562396866 -- kind: conda - name: cuda-cuxxfilt - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-cuxxfilt-11.8.86-0.tar.bz2 - md5: d5e2aa288a115bf8ed23116987b56a9a - arch: x86_64 - platform: linux - size: 298326 - timestamp: 1661507924741 -- kind: conda - name: cuda-demo-suite - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-demo-suite-11.8.86-0.tar.bz2 - md5: 07bdbd4de564326cc7c7677df92d5657 - arch: x86_64 - platform: linux - size: 5212691 - timestamp: 1661484990989 -- kind: conda - name: cuda-documentation - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-documentation-11.8.86-0.tar.bz2 - md5: f3d58829354915696a6cde600382684d - arch: x86_64 - platform: linux - size: 90887 - timestamp: 1661488811822 -- kind: conda - name: cuda-driver-dev - version: 11.8.89 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-driver-dev-11.8.89-0.tar.bz2 - md5: afd39b647ee4eca8a36dc996da4915c4 - arch: x86_64 - platform: linux - size: 16277 - timestamp: 1663787237700 -- kind: conda - name: cuda-gdb - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-gdb-11.8.86-0.tar.bz2 - md5: 0190089d9f2d7f16d2daadbbba38b678 - arch: x86_64 - platform: linux - size: 5013885 - timestamp: 1661489579522 -- kind: conda - name: cuda-libraries - version: 11.8.0 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-libraries-11.8.0-0.tar.bz2 - md5: 3a43d100104e52ac8209a834c82ab231 - depends: - - cuda-cudart >=11.8.89 - - cuda-nvrtc >=11.8.89 - - libcublas >=11.11.3.6 - - libcufft >=10.9.0.58 - - libcufile >=1.4.0.31 - - libcurand >=10.3.0.86 - - libcusolver >=11.4.1.48 - - libcusparse >=11.7.5.86 - - libnpp >=11.8.0.86 - - libnvjpeg >=11.9.0.86 - arch: x86_64 - platform: linux - size: 1535 - timestamp: 1664475490383 -- kind: conda - name: cuda-libraries-dev - version: 11.8.0 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-libraries-dev-11.8.0-0.tar.bz2 - md5: 5428619702b20a8353bff9f3b152bb2f - depends: - - cuda-cccl >=11.8.89 - - cuda-cudart-dev >=11.8.89 - - cuda-driver-dev >=11.8.89 - - cuda-nvrtc-dev >=11.8.89 - - cuda-profiler-api >=11.8.86 - - libcublas-dev >=11.11.3.6 - - libcufft-dev >=10.9.0.58 - - libcufile-dev >=1.4.0.31 - - libcurand-dev >=10.3.0.86 - - libcusolver-dev >=11.4.1.48 - - libcusparse-dev >=11.7.5.86 - - libnpp-dev >=11.8.0.86 - - libnvjpeg-dev >=11.9.0.86 - arch: x86_64 - platform: linux - size: 1571 - timestamp: 1664475500133 -- kind: conda - name: cuda-memcheck - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-memcheck-11.8.86-0.tar.bz2 - md5: 0d658b7c0e0799af3a981eff1c33771c - arch: x86_64 - platform: linux - size: 171911 - timestamp: 1661470265954 -- kind: conda - name: cuda-nsight - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nsight-11.8.86-0.tar.bz2 - md5: f6395abb8428ada738738fd558eba798 - arch: x86_64 - platform: linux - size: 119143043 - timestamp: 1661544543317 -- kind: conda - name: cuda-nsight-compute - version: 11.8.0 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nsight-compute-11.8.0-0.tar.bz2 - md5: 2321698a7ca3b20cc8a5fdcdcd9f8aae - depends: - - nsight-compute >=2022.3.0.22 - arch: x86_64 - platform: linux - size: 1448 - timestamp: 1664475509308 -- kind: conda - name: cuda-nvcc - version: 11.8.89 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvcc-11.8.89-0.tar.bz2 - md5: 33f9af6dac16b94a7dc1111a18fd19bf - arch: x86_64 - platform: linux - size: 53254905 - timestamp: 1663787076437 -- kind: conda - name: cuda-nvdisasm - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvdisasm-11.8.86-0.tar.bz2 - md5: 47de8e90d674c06001a82c1e1502532a - arch: x86_64 - platform: linux - size: 51087785 - timestamp: 1661489072164 -- kind: conda - name: cuda-nvml-dev - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvml-dev-11.8.86-0.tar.bz2 - md5: 0dc7aaa44f459088c5286801d76034c5 - arch: x86_64 - platform: linux - size: 84882 - timestamp: 1661543572982 -- kind: conda - name: cuda-nvprof - version: 11.8.87 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvprof-11.8.87-0.tar.bz2 - md5: a58bfa5a7332b1b71ed88d555a2b934a - arch: x86_64 - platform: linux - size: 4569849 - timestamp: 1661563457664 -- kind: conda - name: cuda-nvprune - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvprune-11.8.86-0.tar.bz2 - md5: 6f1478d39023065741930e23580c9f75 - arch: x86_64 - platform: linux - size: 66127 - timestamp: 1661489036289 -- kind: conda - name: cuda-nvrtc - version: 11.8.89 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvrtc-11.8.89-0.tar.bz2 - md5: f4af75ee32661708c979630cdb8f4987 - arch: x86_64 - platform: linux - size: 20069921 - timestamp: 1663786884512 -- kind: conda - name: cuda-nvrtc-dev - version: 11.8.89 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvrtc-dev-11.8.89-0.tar.bz2 - md5: 953e857784524bf97f58a478cb05f2ac - depends: - - cuda-nvrtc >=11.8.89 - arch: x86_64 - platform: linux - size: 17858592 - timestamp: 1663786894532 -- kind: conda - name: cuda-nvtx - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvtx-11.8.86-0.tar.bz2 - md5: 1825ffc3feb608f2752073935e90bb49 - arch: x86_64 - platform: linux - size: 58436 - timestamp: 1661544565925 -- kind: conda - name: cuda-nvvp - version: 11.8.87 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-nvvp-11.8.87-0.tar.bz2 - md5: e9df05575a736ab3c8f89853bdac736a - depends: - - cuda-nvdisasm - - cuda-nvprof - arch: x86_64 - platform: linux - size: 119905249 - timestamp: 1661563876321 -- kind: conda - name: cuda-profiler-api - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-profiler-api-11.8.86-0.tar.bz2 - md5: a41d5bd148ab7f9e7cc81bed84349d5f - arch: x86_64 - platform: linux - size: 18856 - timestamp: 1661486685944 -- kind: conda - name: cuda-runtime - version: 11.8.0 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-runtime-11.8.0-0.tar.bz2 - md5: 3ca379d762f8d7bd727df9e2c9b30664 - depends: - - cuda-libraries >=11.8.0 - arch: x86_64 - platform: linux - size: 1434 - timestamp: 1664475536765 -- kind: conda - name: cuda-sanitizer-api - version: 11.8.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-sanitizer-api-11.8.86-0.tar.bz2 - md5: f0f85d83cfb619d64e4fb3d00bd6b52a - arch: x86_64 - platform: linux - size: 17426071 - timestamp: 1661489510330 -- kind: conda - name: cuda-toolkit - version: 11.8.0 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-toolkit-11.8.0-0.tar.bz2 - md5: c8daa030f9548d834f5c61b401f262fc - depends: - - cuda-compiler >=11.8.0 - - cuda-documentation >=11.8.86 - - cuda-libraries >=11.8.0 - - cuda-libraries-dev >=11.8.0 - - cuda-nvml-dev >=11.8.86 - - cuda-tools >=11.8.0 - arch: x86_64 - platform: linux - size: 1481 - timestamp: 1664475564507 -- kind: conda - name: cuda-tools - version: 11.8.0 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-tools-11.8.0-0.tar.bz2 - md5: 75bb667ae9c91a2d37ee97d3f99cbae2 - depends: - - cuda-command-line-tools >=11.8.0 - - cuda-visual-tools >=11.8.0 - - gds-tools >=1.4.0.31 - arch: x86_64 - platform: linux - size: 1454 - timestamp: 1664475555196 -- kind: conda - name: cuda-visual-tools - version: 11.8.0 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/cuda-visual-tools-11.8.0-0.tar.bz2 - md5: 4dff31d4235b8b13870ede083de222be - depends: - - cuda-libraries-dev >=11.8.0 - - cuda-nsight >=11.8.86 - - cuda-nsight-compute >=11.8.0 - - cuda-nvml-dev >=11.8.86 - - cuda-nvvp >=11.8.87 - arch: x86_64 - platform: linux - size: 1476 - timestamp: 1664475546019 -- kind: pypi - name: cycler - version: 0.12.1 - url: https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl - sha256: 85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30 - requires_dist: - - ipython ; extra == 'docs' - - matplotlib ; extra == 'docs' - - numpydoc ; extra == 'docs' - - sphinx ; extra == 'docs' - - pytest ; extra == 'tests' - - pytest-cov ; extra == 'tests' - - pytest-xdist ; extra == 'tests' - requires_python: '>=3.8' -- kind: pypi - name: dash - version: 2.17.0 - url: https://files.pythonhosted.org/packages/63/22/bc266b167111e70a2da940e78b78d22fea5b1ee32b512ed0789bd6cc2a9f/dash-2.17.0-py3-none-any.whl - sha256: 2421569023b2cd46ea2d4b2c14fe72c71b7436527a3102219b2265fa361e7c67 - requires_dist: - - flask <3.1, >=1.0.4 - - werkzeug <3.1 - - plotly >=5.0.0 - - dash-html-components ==2.0.0 - - dash-core-components ==2.0.0 - - dash-table ==5.0.0 - - importlib-metadata - - typing-extensions >=4.1.1 - - requests - - retrying - - nest-asyncio - - setuptools - - redis >=3.5.3 ; extra == 'celery' - - celery[redis] >=5.1.2 ; extra == 'celery' - - black ==22.3.0 ; extra == 'ci' - - dash-flow-example ==0.0.5 ; extra == 'ci' - - dash-dangerously-set-inner-html ; extra == 'ci' - - flake8 ==7.0.0 ; extra == 'ci' - - flaky ==3.8.1 ; extra == 'ci' - - flask-talisman ==1.0.0 ; extra == 'ci' - - mimesis <=11.1.0 ; extra == 'ci' - - mock ==4.0.3 ; extra == 'ci' - - numpy <=1.26.3 ; extra == 'ci' - - orjson ==3.9.12 ; extra == 'ci' - - openpyxl ; extra == 'ci' - - pandas >=1.4.0 ; extra == 'ci' - - pyarrow ; extra == 'ci' - - pylint ==3.0.3 ; extra == 'ci' - - pytest-mock ; extra == 'ci' - - pytest-sugar ==0.9.6 ; extra == 'ci' - - pyzmq ==25.1.2 ; extra == 'ci' - - xlrd >=2.0.1 ; extra == 'ci' - - pytest-rerunfailures ; extra == 'ci' - - jupyterlab <4.0.0 ; extra == 'ci' - - flask-compress ; extra == 'compress' - - coloredlogs >=15.0.1 ; extra == 'dev' - - fire >=0.4.0 ; extra == 'dev' - - pyyaml >=5.4.1 ; extra == 'dev' - - diskcache >=5.2.1 ; extra == 'diskcache' - - multiprocess >=0.70.12 ; extra == 'diskcache' - - psutil >=5.8.0 ; extra == 'diskcache' - - beautifulsoup4 >=4.8.2 ; extra == 'testing' - - lxml >=4.6.2 ; extra == 'testing' - - percy >=2.0.2 ; extra == 'testing' - - pytest >=6.0.2 ; extra == 'testing' - - requests[security] >=2.21.0 ; extra == 'testing' - - selenium <=4.2.0, >=3.141.0 ; extra == 'testing' - - waitress >=1.4.4 ; extra == 'testing' - - multiprocess >=0.70.12 ; extra == 'testing' - - psutil >=5.8.0 ; extra == 'testing' - - dash-testing-stub >=0.0.2 ; extra == 'testing' - - cryptography <3.4 ; python_version < '3.7' and extra == 'testing' - requires_python: '>=3.8' -- kind: pypi - name: dash-core-components - version: 2.0.0 - url: https://files.pythonhosted.org/packages/00/9e/a29f726e84e531a36d56cff187e61d8c96d2cc253c5bcef9a7695acb7e6a/dash_core_components-2.0.0-py3-none-any.whl - sha256: 52b8e8cce13b18d0802ee3acbc5e888cb1248a04968f962d63d070400af2e346 -- kind: pypi - name: dash-html-components - version: 2.0.0 - url: https://files.pythonhosted.org/packages/75/65/1b16b853844ef59b2742a7de74a598f376ac0ab581f0dcc34db294e5c90e/dash_html_components-2.0.0-py3-none-any.whl - sha256: b42cc903713c9706af03b3f2548bda4be7307a7cf89b7d6eae3da872717d1b63 -- kind: pypi - name: dash-table - version: 5.0.0 - url: https://files.pythonhosted.org/packages/da/ce/43f77dc8e7bbad02a9f88d07bf794eaf68359df756a28bb9f2f78e255bb1/dash_table-5.0.0-py3-none-any.whl - sha256: 19036fa352bb1c11baf38068ec62d172f0515f73ca3276c79dee49b95ddc16c9 -- kind: conda - name: dav1d - version: 1.2.1 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda - sha256: 22053a5842ca8ee1cf8e1a817138cdb5e647eb2c46979f84153f6ad7bde73020 - md5: 418c6ca5929a611cbd69204907a83995 - depends: - - libgcc-ng >=12 - license: BSD-2-Clause - license_family: BSD - size: 760229 - timestamp: 1685695754230 -- kind: conda - name: dbus - version: 1.13.6 - build: h5008d03_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2 - sha256: 8f5f995699a2d9dbdd62c61385bfeeb57c82a681a7c8c5313c395aa0ccab68a5 - md5: ecfff944ba3960ecb334b9a2663d708d - depends: - - expat >=2.4.2,<3.0a0 - - libgcc-ng >=9.4.0 - - libglib >=2.70.2,<3.0a0 - license: GPL-2.0-or-later - license_family: GPL - size: 618596 - timestamp: 1640112124844 -- kind: pypi - name: debugpy - version: 1.8.1 - url: https://files.pythonhosted.org/packages/7a/27/78d5cf9c7aba43f8341e78273ab776913d2d33beb581ec39b65e56a0db77/debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e - requires_python: '>=3.8' -- kind: pypi - name: decorator - version: 5.1.1 - url: https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl - sha256: b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186 - requires_python: '>=3.5' -- kind: pypi - name: defusedxml - version: 0.7.1 - url: https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl - sha256: a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61 - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' -- kind: pypi - name: descartes - version: 1.1.0 - url: https://files.pythonhosted.org/packages/e5/b6/1ed2eb03989ae574584664985367ba70cd9cf8b32ee8cad0e8aaeac819f3/descartes-1.1.0-py3-none-any.whl - sha256: 4c62dc41109689d03e4b35de0a2bcbdeeb81047badc607c4415d5c753bd683af - requires_dist: - - matplotlib -- kind: pypi - name: dill - version: 0.3.8 - url: https://files.pythonhosted.org/packages/c9/7a/cef76fd8438a42f96db64ddaa85280485a9c395e7df3db8158cfec1eee34/dill-0.3.8-py3-none-any.whl - sha256: c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7 - requires_dist: - - objgraph >=1.7.2 ; extra == 'graph' - - gprof2dot >=2022.7.29 ; extra == 'profile' - requires_python: '>=3.8' -- kind: pypi - name: docker-pycreds - version: 0.4.0 - url: https://files.pythonhosted.org/packages/f5/e8/f6bd1eee09314e7e6dee49cbe2c5e22314ccdb38db16c9fc72d2fa80d054/docker_pycreds-0.4.0-py2.py3-none-any.whl - sha256: 7266112468627868005106ec19cd0d722702d2b7d5912a28e19b826c3d37af49 - requires_dist: - - six >=1.4.0 -- kind: pypi - name: docstring-parser - version: '0.16' - url: https://files.pythonhosted.org/packages/d5/7c/e9fcff7623954d86bdc17782036cbf715ecab1bec4847c008557affe1ca8/docstring_parser-0.16-py3-none-any.whl - sha256: bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637 - requires_python: '>=3.6,<4.0' -- kind: pypi - name: docutils - version: '0.16' - url: https://files.pythonhosted.org/packages/81/44/8a15e45ffa96e6cf82956dd8d7af9e666357e16b0d93b253903475ee947f/docutils-0.16-py2.py3-none-any.whl - sha256: 0c5b78adfbf7762415433f5515cd5c9e762339e23369dbe8000d84a4bf4ab3af - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' -- kind: pypi - name: dulwich - version: 0.22.1 - url: https://files.pythonhosted.org/packages/62/45/c663da77e3799057e561432b74967f3348cc985a2bdab433a7b01106611c/dulwich-0.22.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: b03092399f0f5d3e112405b890128afdb9e1f203eafb812f5d9105b0f5fac9d4 - requires_dist: - - urllib3 >=1.25 - - typing-extensions ; python_version <= '3.7' - - setuptools ; python_version >= '3.12' - - fastimport ; extra == 'fastimport' - - urllib3 >=1.24.1 ; extra == 'https' - - paramiko ; extra == 'paramiko' - - gpg ; extra == 'pgp' - requires_python: '>=3.7' -- kind: conda - name: eigen - version: 3.4.0 - build: h00ab1b0_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/eigen-3.4.0-h00ab1b0_0.conda - sha256: 53b15a98aadbe0704479bacaf7a5618fcb32d1577be320630674574241639b34 - md5: b1b879d6d093f55dd40d58b5eb2f0699 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: MPL-2.0 - license_family: MOZILLA - size: 1088433 - timestamp: 1690272126173 -- kind: pypi - name: embreex - version: 2.17.7.post4 - url: https://files.pythonhosted.org/packages/90/c7/f4abf09c6109c975e462c72ea4f9e2d72d78e20325dafb151c8e9789a31d/embreex-2.17.7.post4-cp310-cp310-manylinux_2_28_x86_64.whl - sha256: 0750fba99a77049baff6b25c10206d328ff385ee2e35d6147423b0bba50c904c - requires_dist: - - numpy ; python_version < '3.12' - - numpy >=1.26.0b1 ; python_version >= '3.12' -- kind: pypi - name: everett - version: 3.1.0 - url: https://files.pythonhosted.org/packages/91/9a/d882fd7562208456236fb2e62b762bf16fbc9ecde842bb871f676ca0f7e1/everett-3.1.0-py2.py3-none-any.whl - sha256: db13891b849e45e54faea93ee79881d12458c5378f5b9b7f806eeff03ce1de3c - requires_dist: - - configobj ; extra == 'ini' - - pyyaml ; extra == 'yaml' -- kind: pypi - name: exceptiongroup - version: 1.2.1 - url: https://files.pythonhosted.org/packages/01/90/79fe92dd413a9cab314ef5c591b5aa9b9ba787ae4cadab75055b0ae00b33/exceptiongroup-1.2.1-py3-none-any.whl - sha256: 5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad - requires_dist: - - pytest >=6 ; extra == 'test' - requires_python: '>=3.7' -- kind: pypi - name: executing - version: 2.0.1 - url: https://files.pythonhosted.org/packages/80/03/6ea8b1b2a5ab40a7a60dc464d3daa7aa546e0a74d74a9f8ff551ea7905db/executing-2.0.1-py2.py3-none-any.whl - sha256: eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc - requires_dist: - - asttokens >=2.1.0 ; extra == 'tests' - - ipython ; extra == 'tests' - - pytest ; extra == 'tests' - - coverage ; extra == 'tests' - - coverage-enable-subprocess ; extra == 'tests' - - littleutils ; extra == 'tests' - - rich ; python_version >= '3.11' and extra == 'tests' - requires_python: '>=3.5' -- kind: conda - name: expat - version: 2.6.2 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/expat-2.6.2-h59595ed_0.conda - sha256: 89916c536ae5b85bb8bf0cfa27d751e274ea0911f04e4a928744735c14ef5155 - md5: 53fb86322bdb89496d7579fe3f02fd61 - depends: - - libexpat 2.6.2 h59595ed_0 - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 137627 - timestamp: 1710362144873 -- kind: pypi - name: fastjsonschema - version: 2.19.1 - url: https://files.pythonhosted.org/packages/9c/b9/79691036d4a8f9857e74d1728b23f34f583b81350a27492edda58d5604e1/fastjsonschema-2.19.1-py3-none-any.whl - sha256: 3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0 - requires_dist: - - colorama ; extra == 'devel' - - jsonschema ; extra == 'devel' - - json-spec ; extra == 'devel' - - pylint ; extra == 'devel' - - pytest ; extra == 'devel' - - pytest-benchmark ; extra == 'devel' - - pytest-cache ; extra == 'devel' - - validictory ; extra == 'devel' -- kind: conda - name: ffmpeg - version: 7.0.0 - build: gpl_hdd1146e_100 - build_number: 100 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ffmpeg-7.0.0-gpl_hdd1146e_100.conda - sha256: 39a457f10212176e161ecd7ea4c182566afe6922576dc2c7609a87c730c2451d - md5: 0d4bb500ba9958dacb59c7e7e6b5abe0 - depends: - - __glibc >=2.17,<3.0.a0 - - aom >=3.9.0,<3.10.0a0 - - bzip2 >=1.0.8,<2.0a0 - - dav1d >=1.2.1,<1.2.2.0a0 - - fontconfig >=2.14.2,<3.0a0 - - fonts-conda-ecosystem - - freetype >=2.12.1,<3.0a0 - - gmp >=6.3.0,<7.0a0 - - gnutls >=3.7.9,<3.8.0a0 - - harfbuzz >=8.4.0,<9.0a0 - - lame >=3.100,<3.101.0a0 - - libass >=0.17.1,<0.17.2.0a0 - - libgcc-ng >=12 - - libiconv >=1.17,<2.0a0 - - libopenvino >=2024.0.0,<2024.0.1.0a0 - - libopenvino-auto-batch-plugin >=2024.0.0,<2024.0.1.0a0 - - libopenvino-auto-plugin >=2024.0.0,<2024.0.1.0a0 - - libopenvino-hetero-plugin >=2024.0.0,<2024.0.1.0a0 - - libopenvino-intel-cpu-plugin >=2024.0.0,<2024.0.1.0a0 - - libopenvino-intel-gpu-plugin >=2024.0.0,<2024.0.1.0a0 - - libopenvino-ir-frontend >=2024.0.0,<2024.0.1.0a0 - - libopenvino-onnx-frontend >=2024.0.0,<2024.0.1.0a0 - - libopenvino-paddle-frontend >=2024.0.0,<2024.0.1.0a0 - - libopenvino-pytorch-frontend >=2024.0.0,<2024.0.1.0a0 - - libopenvino-tensorflow-frontend >=2024.0.0,<2024.0.1.0a0 - - libopenvino-tensorflow-lite-frontend >=2024.0.0,<2024.0.1.0a0 - - libopus >=1.3.1,<2.0a0 - - libstdcxx-ng >=12 - - libva >=2.21.0,<3.0a0 - - libvpx >=1.14.0,<1.15.0a0 - - libxcb >=1.15,<1.16.0a0 - - libxml2 >=2.12.6,<3.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - openh264 >=2.4.1,<2.4.2.0a0 - - svt-av1 >=2.0.0,<2.0.1.0a0 - - x264 >=1!164.3095,<1!165 - - x265 >=3.5,<3.6.0a0 - - xorg-libx11 >=1.8.9,<2.0a0 - - xz >=5.2.6,<6.0a0 - license: GPL-2.0-or-later - license_family: GPL - size: 10099146 - timestamp: 1714840178324 -- kind: conda - name: filelock - version: 3.14.0 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/filelock-3.14.0-pyhd8ed1ab_0.conda - sha256: 6031be667e1b0cc0dee713f1cbca887cdee4daafa8bac478da33096f3147d38b - md5: 831d85ae0acfba31b8efd0f0d07da736 - depends: - - python >=3.7 - license: Unlicense - purls: - - pkg:pypi/filelock - size: 15902 - timestamp: 1714422911808 -- kind: pypi - name: fire - version: 0.6.0 - url: https://files.pythonhosted.org/packages/1b/1b/84c63f592ecdfbb3d77d22a8d93c9b92791e4fa35677ad71a7d6449100f8/fire-0.6.0.tar.gz - sha256: 54ec5b996ecdd3c0309c800324a0703d6da512241bc73b553db959d98de0aa66 - requires_dist: - - six - - termcolor - - enum34 ; python_version < '3.4' -- kind: conda - name: flann - version: 1.9.2 - build: h2b5ea80_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/flann-1.9.2-h2b5ea80_0.conda - sha256: eda6991f3c85b8263fec8fb83fc3d64e3d28963659f1c3f18067487d40d69491 - md5: 0846ae36cd85f5e469b630ee74719ad8 - depends: - - _openmp_mutex >=4.5 - - hdf5 >=1.14.2,<1.14.4.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - lz4-c >=1.9.3,<1.10.0a0 - license: BSD-3-Clause - license_family: BSD - size: 1565184 - timestamp: 1697891385570 -- kind: pypi - name: flask - version: 3.0.3 - url: https://files.pythonhosted.org/packages/61/80/ffe1da13ad9300f87c93af113edd0638c75138c42a0994becfacac078c06/flask-3.0.3-py3-none-any.whl - sha256: 34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3 - requires_dist: - - werkzeug >=3.0.0 - - jinja2 >=3.1.2 - - itsdangerous >=2.1.2 - - click >=8.1.3 - - blinker >=1.6.2 - - importlib-metadata >=3.6.0 ; python_version < '3.10' - - asgiref >=3.2 ; extra == 'async' - - python-dotenv ; extra == 'dotenv' - requires_python: '>=3.8' -- kind: conda - name: font-ttf-dejavu-sans-mono - version: '2.37' - build: hab24e00_0 - subdir: noarch - noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2 - sha256: 58d7f40d2940dd0a8aa28651239adbf5613254df0f75789919c4e6762054403b - md5: 0c96522c6bdaed4b1566d11387caaf45 - license: BSD-3-Clause - license_family: BSD - size: 397370 - timestamp: 1566932522327 -- kind: conda - name: font-ttf-inconsolata - version: '3.000' - build: h77eed37_0 - subdir: noarch - noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2 - sha256: c52a29fdac682c20d252facc50f01e7c2e7ceac52aa9817aaf0bb83f7559ec5c - md5: 34893075a5c9e55cdafac56607368fc6 - license: OFL-1.1 - license_family: Other - size: 96530 - timestamp: 1620479909603 -- kind: conda - name: font-ttf-source-code-pro - version: '2.038' - build: h77eed37_0 - subdir: noarch - noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2 - sha256: 00925c8c055a2275614b4d983e1df637245e19058d79fc7dd1a93b8d9fb4b139 - md5: 4d59c254e01d9cde7957100457e2d5fb - license: OFL-1.1 - license_family: Other - size: 700814 - timestamp: 1620479612257 -- kind: conda - name: font-ttf-ubuntu - version: '0.83' - build: h77eed37_2 - build_number: 2 - subdir: noarch - noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_2.conda - sha256: c940f6e969143e13a3a9660abb3c7e7e23b8319efb29dbdd5dee0b9939236e13 - md5: cbbe59391138ea5ad3658c76912e147f - license: LicenseRef-Ubuntu-Font-Licence-Version-1.0 - license_family: Other - size: 1622566 - timestamp: 1714483134319 -- kind: conda - name: fontconfig - version: 2.14.2 - build: h14ed4e7_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.14.2-h14ed4e7_0.conda - sha256: 155d534c9037347ea7439a2c6da7c24ffec8e5dd278889b4c57274a1d91e0a83 - md5: 0f69b688f52ff6da70bccb7ff7001d1d - depends: - - expat >=2.5.0,<3.0a0 - - freetype >=2.12.1,<3.0a0 - - libgcc-ng >=12 - - libuuid >=2.32.1,<3.0a0 - - libzlib >=1.2.13,<1.3.0a0 - license: MIT - license_family: MIT - size: 272010 - timestamp: 1674828850194 -- kind: conda - name: fonts-conda-ecosystem - version: '1' - build: '0' - subdir: noarch - noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2 - sha256: a997f2f1921bb9c9d76e6fa2f6b408b7fa549edd349a77639c9fe7a23ea93e61 - md5: fee5683a3f04bd15cbd8318b096a27ab - depends: - - fonts-conda-forge - license: BSD-3-Clause - license_family: BSD - size: 3667 - timestamp: 1566974674465 -- kind: conda - name: fonts-conda-forge - version: '1' - build: '0' - subdir: noarch - noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-0.tar.bz2 - sha256: 53f23a3319466053818540bcdf2091f253cbdbab1e0e9ae7b9e509dcaa2a5e38 - md5: f766549260d6815b0c52253f1fb1bb29 - depends: - - font-ttf-dejavu-sans-mono - - font-ttf-inconsolata - - font-ttf-source-code-pro - - font-ttf-ubuntu - license: BSD-3-Clause - license_family: BSD - size: 4102 - timestamp: 1566932280397 -- kind: pypi - name: fonttools - version: 4.51.0 - url: https://files.pythonhosted.org/packages/67/09/e09ee013d9d6f2f006147e5fc2b4d807eb2931f4f890c2d4f711e10391d7/fonttools-4.51.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 180194c7fe60c989bb627d7ed5011f2bef1c4d36ecf3ec64daec8302f1ae0716 - requires_dist: - - fs <3, >=2.2.0 ; extra == 'all' - - lxml >=4.0 ; extra == 'all' - - zopfli >=0.1.4 ; extra == 'all' - - lz4 >=1.7.4.2 ; extra == 'all' - - pycairo ; extra == 'all' - - matplotlib ; extra == 'all' - - sympy ; extra == 'all' - - skia-pathops >=0.5.0 ; extra == 'all' - - uharfbuzz >=0.23.0 ; extra == 'all' - - brotlicffi >=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'all' - - scipy ; platform_python_implementation != 'PyPy' and extra == 'all' - - brotli >=1.0.1 ; platform_python_implementation == 'CPython' and extra == 'all' - - munkres ; platform_python_implementation == 'PyPy' and extra == 'all' - - unicodedata2 >=15.1.0 ; python_version <= '3.12' and extra == 'all' - - xattr ; sys_platform == 'darwin' and extra == 'all' - - lz4 >=1.7.4.2 ; extra == 'graphite' - - pycairo ; extra == 'interpolatable' - - scipy ; platform_python_implementation != 'PyPy' and extra == 'interpolatable' - - munkres ; platform_python_implementation == 'PyPy' and extra == 'interpolatable' - - lxml >=4.0 ; extra == 'lxml' - - skia-pathops >=0.5.0 ; extra == 'pathops' - - matplotlib ; extra == 'plot' - - uharfbuzz >=0.23.0 ; extra == 'repacker' - - sympy ; extra == 'symfont' - - xattr ; sys_platform == 'darwin' and extra == 'type1' - - fs <3, >=2.2.0 ; extra == 'ufo' - - unicodedata2 >=15.1.0 ; python_version <= '3.12' and extra == 'unicode' - - zopfli >=0.1.4 ; extra == 'woff' - - brotlicffi >=0.8.0 ; platform_python_implementation != 'CPython' and extra == 'woff' - - brotli >=1.0.1 ; platform_python_implementation == 'CPython' and extra == 'woff' - requires_python: '>=3.8' -- kind: pypi - name: fqdn - version: 1.5.1 - url: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - sha256: 3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014 - requires_dist: - - cached-property >=1.3.0 ; python_version < '3.8' - requires_python: '>=2.7,!=3.0,!=3.1,!=3.2,!=3.3,!=3.4,<4' -- kind: conda - name: freeimage - version: 3.18.0 - build: h4b96d29_20 - build_number: 20 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/freeimage-3.18.0-h4b96d29_20.conda - sha256: 07d34a47867f15878dff3d5ae11a7fa24bb03587878ce1798314d03fc6d3d6a5 - md5: 41069afbb9fb02e6e19dd80b4a2c46e7 - depends: - - imath >=3.1.11,<3.1.12.0a0 - - jxrlib >=1.1,<1.2.0a0 - - libgcc-ng >=12 - - libjpeg-turbo >=3.0.0,<4.0a0 - - libpng >=1.6.43,<1.7.0a0 - - libraw >=0.21.1,<0.22.0a0 - - libstdcxx-ng >=12 - - libtiff >=4.6.0,<4.7.0a0 - - libwebp-base >=1.3.2,<2.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - openexr >=3.2.2,<3.3.0a0 - - openjpeg >=2.5.2,<3.0a0 - license: GPL-2.0-or-later OR GPL-3.0-or-later OR FreeImage - size: 461394 - timestamp: 1709288677517 -- kind: conda - name: freetype - version: 2.12.1 - build: h267a509_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/freetype-2.12.1-h267a509_2.conda - sha256: b2e3c449ec9d907dd4656cb0dc93e140f447175b125a3824b31368b06c666bb6 - md5: 9ae35c3d96db2c94ce0cef86efdfa2cb - depends: - - libgcc-ng >=12 - - libpng >=1.6.39,<1.7.0a0 - - libzlib >=1.2.13,<1.3.0a0 - license: GPL-2.0-only OR FTL - size: 634972 - timestamp: 1694615932610 -- kind: conda - name: fribidi - version: 1.0.10 - build: h36c2ea0_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/fribidi-1.0.10-h36c2ea0_0.tar.bz2 - sha256: 5d7b6c0ee7743ba41399e9e05a58ccc1cfc903942e49ff6f677f6e423ea7a627 - md5: ac7bc6a654f8f41b352b38f4051135f8 - depends: - - libgcc-ng >=7.5.0 - license: LGPL-2.1 - size: 114383 - timestamp: 1604416621168 -- kind: pypi - name: gdown - version: 5.1.0 - url: https://files.pythonhosted.org/packages/cb/56/f4845ed78723a4eb8eb22bcfcb46e1157a462c78c0a5ed318c68c98f9a79/gdown-5.1.0-py3-none-any.whl - sha256: 421530fd238fa15d41ba43219a79fdc28efe8ac11022173abad333701b77de2c - requires_dist: - - beautifulsoup4 - - filelock - - requests[socks] - - tqdm - - build ; extra == 'test' - - mypy ; extra == 'test' - - pytest ; extra == 'test' - - pytest-xdist ; extra == 'test' - - ruff ; extra == 'test' - - twine ; extra == 'test' - - types-requests ; extra == 'test' - requires_python: '>=3.8' -- kind: conda - name: gds-tools - version: 1.4.0.31 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/gds-tools-1.4.0.31-0.tar.bz2 - md5: 94165b72994808d935d15cc3667100c9 - depends: - - libcufile >=1.4.0.31 - arch: x86_64 - platform: linux - size: 1680 - timestamp: 1655921106799 -- kind: conda - name: gettext - version: 0.22.5 - build: h59595ed_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/gettext-0.22.5-h59595ed_2.conda - sha256: 386181254ddd2aed1fccdfc217da5b6545f6df4e9979ad8e08f5e91e22eaf7dc - md5: 219ba82e95d7614cf7140d2a4afc0926 - depends: - - gettext-tools 0.22.5 h59595ed_2 - - libasprintf 0.22.5 h661eb56_2 - - libasprintf-devel 0.22.5 h661eb56_2 - - libgcc-ng >=12 - - libgettextpo 0.22.5 h59595ed_2 - - libgettextpo-devel 0.22.5 h59595ed_2 - - libstdcxx-ng >=12 - license: LGPL-2.1-or-later AND GPL-3.0-or-later - size: 475058 - timestamp: 1712512357949 -- kind: conda - name: gettext-tools - version: 0.22.5 - build: h59595ed_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/gettext-tools-0.22.5-h59595ed_2.conda - sha256: 67d7b1d6fe4f1c516df2000640ec7dcfebf3ff6ea0785f0276870e730c403d33 - md5: 985f2f453fb72408d6b6f1be0f324033 - depends: - - libgcc-ng >=12 - license: GPL-3.0-or-later - license_family: GPL - size: 2728420 - timestamp: 1712512328692 -- kind: conda - name: gflags - version: 2.2.2 - build: he1b5a44_1004 - build_number: 1004 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/gflags-2.2.2-he1b5a44_1004.tar.bz2 - sha256: a853c0cacf53cfc59e1bca8d6e5cdfe9f38fce836f08c2a69e35429c2a492e77 - md5: cddaf2c63ea4a5901cf09524c490ecdc - depends: - - libgcc-ng >=7.5.0 - - libstdcxx-ng >=7.5.0 - license: BSD-3-Clause - license_family: BSD - size: 116549 - timestamp: 1594303828933 -- kind: pypi - name: gitdb - version: 4.0.11 - url: https://files.pythonhosted.org/packages/fd/5b/8f0c4a5bb9fd491c277c21eff7ccae71b47d43c4446c9d0c6cff2fe8c2c4/gitdb-4.0.11-py3-none-any.whl - sha256: 81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4 - requires_dist: - - smmap <6, >=3.0.1 - requires_python: '>=3.7' -- kind: pypi - name: gitpython - version: 3.1.43 - url: https://files.pythonhosted.org/packages/e9/bd/cc3a402a6439c15c3d4294333e13042b915bbeab54edc457c723931fed3f/GitPython-3.1.43-py3-none-any.whl - sha256: eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff - requires_dist: - - gitdb <5, >=4.0.1 - - typing-extensions >=3.7.4.3 ; python_version < '3.8' - - sphinx ==4.3.2 ; extra == 'doc' - - sphinx-rtd-theme ; extra == 'doc' - - sphinxcontrib-applehelp <=1.0.4, >=1.0.2 ; extra == 'doc' - - sphinxcontrib-devhelp ==1.0.2 ; extra == 'doc' - - sphinxcontrib-htmlhelp <=2.0.1, >=2.0.0 ; extra == 'doc' - - sphinxcontrib-qthelp ==1.0.3 ; extra == 'doc' - - sphinxcontrib-serializinghtml ==1.1.5 ; extra == 'doc' - - sphinx-autodoc-typehints ; extra == 'doc' - - coverage[toml] ; extra == 'test' - - ddt !=1.4.3, >=1.1.1 ; extra == 'test' - - mypy ; extra == 'test' - - pre-commit ; extra == 'test' - - pytest >=7.3.1 ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-instafail ; extra == 'test' - - pytest-mock ; extra == 'test' - - pytest-sugar ; extra == 'test' - - typing-extensions ; python_version < '3.11' and extra == 'test' - - mock ; python_version < '3.8' and extra == 'test' - requires_python: '>=3.7' -- kind: conda - name: glew - version: 2.1.0 - build: h9c3ff4c_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/glew-2.1.0-h9c3ff4c_2.tar.bz2 - sha256: 86f5484e38f4604f7694b14f64238e932e8fd8d7364e86557f4911eded2843ae - md5: fb05eb5c47590b247658243d27fc32f1 - depends: - - libgcc-ng >=9.3.0 - - libglu - - libstdcxx-ng >=9.3.0 - - xorg-libx11 - - xorg-libxext - license: BSD-3-Clause - license_family: BSD - size: 662569 - timestamp: 1607113198887 -- kind: conda - name: glib - version: 2.80.0 - build: hf2295e7_6 - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/glib-2.80.0-hf2295e7_6.conda - sha256: 186e366c3a48c07830aa94dfc84616155bdfd08e9b73cb8e482c6ca84a550d3e - md5: a1e026a82a562b443845db5614ca568a - depends: - - glib-tools 2.80.0 hde27a5a_6 - - libffi >=3.4,<4.0a0 - - libgcc-ng >=12 - - libglib 2.80.0 hf2295e7_6 - - python * - license: LGPL-2.1-or-later - size: 597788 - timestamp: 1713639483074 -- kind: conda - name: glib-tools - version: 2.80.0 - build: hde27a5a_6 - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/glib-tools-2.80.0-hde27a5a_6.conda - sha256: fb63c92ba2b08aad574404c6229d45f12dc78309ff7a540f1e8d941a8a075074 - md5: a9d23c02485c5cf055f9ac90eb9c9c63 - depends: - - libgcc-ng >=12 - - libglib 2.80.0 hf2295e7_6 - license: LGPL-2.1-or-later - size: 113049 - timestamp: 1713639447140 -- kind: conda - name: glog - version: 0.7.0 - build: hed5481d_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/glog-0.7.0-hed5481d_0.conda - sha256: 19f41db8f189ed9caec68ffb9ec97d5518b5ee6b58e0636d185f392f688a84a1 - md5: a9ea19c48e11754899299f8123070f4e - depends: - - gflags >=2.2.2,<2.3.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: BSD-3-Clause - license_family: BSD - size: 143596 - timestamp: 1708260910243 -- kind: conda - name: gmp - version: 6.3.0 - build: h59595ed_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/gmp-6.3.0-h59595ed_1.conda - sha256: cfc4202c23d6895d9c84042d08d5cda47d597772df870d4d2a10fc86dded5576 - md5: e358c7c5f6824c272b5034b3816438a7 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: GPL-2.0-or-later OR LGPL-3.0-or-later - size: 569852 - timestamp: 1710169507479 -- kind: conda - name: gmpy2 - version: 2.1.5 - build: py310hc3586ac_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/gmpy2-2.1.5-py310hc3586ac_0.conda - sha256: 0d78fa92c9f794e0e2dce37f63388f8d45d211e513f7ed52953035b229745ae7 - md5: 4bc44690e556dd18ecf3a66cbad72d2f - depends: - - gmp >=6.3.0,<7.0a0 - - libgcc-ng >=12 - - mpc >=1.3.1,<2.0a0 - - mpfr >=4.2.1,<5.0a0 - - python >=3.10,<3.11.0a0 - - python_abi 3.10.* *_cp310 - license: LGPL-3.0-or-later - license_family: LGPL - purls: - - pkg:pypi/gmpy2 - size: 204071 - timestamp: 1713794554076 -- kind: conda - name: gnutls - version: 3.7.9 - build: hb077bed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/gnutls-3.7.9-hb077bed_0.conda - sha256: 52d824a5d2b8a5566cd469cae6ad6920469b5a15b3e0ddc609dd29151be71be2 - md5: 33eded89024f21659b1975886a4acf70 - depends: - - libgcc-ng >=12 - - libidn2 >=2,<3.0a0 - - libstdcxx-ng >=12 - - libtasn1 >=4.19.0,<5.0a0 - - nettle >=3.9.1,<3.10.0a0 - - p11-kit >=0.24.1,<0.25.0a0 - license: LGPL-2.1-or-later - license_family: LGPL - size: 1974935 - timestamp: 1701111180127 -- kind: conda - name: graphite2 - version: 1.3.13 - build: h59595ed_1003 - build_number: 1003 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/graphite2-1.3.13-h59595ed_1003.conda - sha256: 0595b009f20f8f60f13a6398e7cdcbd2acea5f986633adcf85f5a2283c992add - md5: f87c7b7c2cb45f323ffbce941c78ab7c - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: LGPL-2.0-or-later - license_family: LGPL - size: 96855 - timestamp: 1711634169756 -- kind: pypi - name: grpcio - version: 1.63.0 - url: https://files.pythonhosted.org/packages/47/82/5f51b0ac0e670aa6551f351c6c8a479149a36c413dd76db4b98d26dddbea/grpcio-1.63.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: cf8dae9cc0412cb86c8de5a8f3be395c5119a370f3ce2e69c8b7d46bb9872c8d - requires_dist: - - grpcio-tools >=1.63.0 ; extra == 'protobuf' - requires_python: '>=3.8' -- kind: pypi - name: gsplat - version: 1.0.0 - url: https://files.pythonhosted.org/packages/53/71/d9bf12b11f608f0ad078fa962a9ab61a2cf28fa9739293a1e842656bc419/gsplat-1.0.0-py3-none-any.whl - sha256: a21eead19150e80a0531dd24e5d717c67892cb381657c8411ec8b318b293a032 - requires_dist: - - jaxtyping - - rich >=12 - - torch - - typing-extensions ; python_version < '3.8' - - black[jupyter] ==22.3.0 ; extra == 'dev' - - isort ==5.10.1 ; extra == 'dev' - - pylint ==2.13.4 ; extra == 'dev' - - pytest ==7.1.2 ; extra == 'dev' - - pytest-xdist ==2.5.0 ; extra == 'dev' - - typeguard >=2.13.3 ; extra == 'dev' - - pyyaml ==6.0 ; extra == 'dev' - - build ; extra == 'dev' - - twine ; extra == 'dev' - - ninja ; extra == 'dev' - requires_python: '>=3.7' -- kind: conda - name: gst-plugins-base - version: 1.24.3 - build: h9ad1361_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/gst-plugins-base-1.24.3-h9ad1361_0.conda - sha256: bfcd03bde2be5293dfb901639778bfe08bc17c59c4935d43cc981953196d7b82 - md5: 8fb0e954c616bb0f9389efac4b4ed44b - depends: - - __glibc >=2.17,<3.0.a0 - - alsa-lib >=1.2.11,<1.3.0a0 - - gstreamer 1.24.3 haf2f30d_0 - - libexpat >=2.6.2,<3.0a0 - - libgcc-ng >=12 - - libglib >=2.80.0,<3.0a0 - - libogg >=1.3.4,<1.4.0a0 - - libopus >=1.3.1,<2.0a0 - - libpng >=1.6.43,<1.7.0a0 - - libstdcxx-ng >=12 - - libvorbis >=1.3.7,<1.4.0a0 - - libxcb >=1.15,<1.16.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - xorg-libx11 >=1.8.9,<2.0a0 - - xorg-libxau >=1.0.11,<2.0a0 - - xorg-libxext >=1.3.4,<2.0a0 - - xorg-libxrender >=0.9.11,<0.10.0a0 - license: LGPL-2.0-or-later - license_family: LGPL - size: 2794610 - timestamp: 1714842288833 -- kind: conda - name: gstreamer - version: 1.24.3 - build: haf2f30d_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/gstreamer-1.24.3-haf2f30d_0.conda - sha256: 020f78890f16e2352f8e9ac12ada652fa0465761aa61b95100c9331e7a1c5742 - md5: f3df87cc9ef0b5113bff55aefcbcafd5 - depends: - - __glibc >=2.17,<3.0.a0 - - glib >=2.80.0,<3.0a0 - - libgcc-ng >=12 - - libglib >=2.80.0,<3.0a0 - - libiconv >=1.17,<2.0a0 - - libstdcxx-ng >=12 - license: LGPL-2.0-or-later - license_family: LGPL - size: 2024018 - timestamp: 1714842147120 -- kind: pypi - name: h11 - version: 0.14.0 - url: https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl - sha256: e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 - requires_dist: - - typing-extensions ; python_version < '3.8' - requires_python: '>=3.7' -- kind: pypi - name: h5py - version: 3.11.0 - url: https://files.pythonhosted.org/packages/94/00/94bf8573e7487b7c37f2b613fc381880d48ec2311f2e859b8a5817deb4df/h5py-3.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 77b19a40788e3e362b54af4dcf9e6fde59ca016db2c61360aa30b47c7b7cef00 - requires_dist: - - numpy >=1.17.3 - requires_python: '>=3.8' -- kind: conda - name: harfbuzz - version: 8.4.0 - build: h3d44ed6_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/harfbuzz-8.4.0-h3d44ed6_0.conda - sha256: d27441d53498f28a36a1612d8f767bae0418076e9c08dcd2cd511c8439d2fb4d - md5: 27f46291a6aaa3c2a4f798ebd35a7ddb - depends: - - cairo >=1.18.0,<2.0a0 - - freetype >=2.12.1,<3.0a0 - - graphite2 - - icu >=73.2,<74.0a0 - - libgcc-ng >=12 - - libglib >=2.80.0,<3.0a0 - - libstdcxx-ng >=12 - license: MIT - license_family: MIT - size: 1587652 - timestamp: 1713957638950 -- kind: conda - name: hdf5 - version: 1.14.3 - build: nompi_h4f84152_101 - build_number: 101 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.3-nompi_h4f84152_101.conda - sha256: e7d2591bc77d47e9f3fc57d94a817dc9385f4079d930a93475fe45aa2ba81d47 - md5: 7e98860d08eea82c8057abd78864fcb4 - depends: - - libaec >=1.1.3,<2.0a0 - - libcurl >=8.7.1,<9.0a0 - - libgcc-ng >=12 - - libgfortran-ng - - libgfortran5 >=12.3.0 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - openssl >=3.3.0,<4.0a0 - license: BSD-3-Clause - license_family: BSD - size: 3884115 - timestamp: 1714575562551 -- kind: pypi - name: httpcore - version: 1.0.5 - url: https://files.pythonhosted.org/packages/78/d4/e5d7e4f2174f8a4d63c8897d79eb8fe2503f7ecc03282fee1fa2719c2704/httpcore-1.0.5-py3-none-any.whl - sha256: 421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5 - requires_dist: - - certifi - - h11 <0.15, >=0.13 - - anyio <5.0, >=4.0 ; extra == 'asyncio' - - h2 <5, >=3 ; extra == 'http2' - - socksio ==1.* ; extra == 'socks' - - trio <0.26.0, >=0.22.0 ; extra == 'trio' - requires_python: '>=3.8' -- kind: pypi - name: httpx - version: 0.27.0 - url: https://files.pythonhosted.org/packages/41/7b/ddacf6dcebb42466abd03f368782142baa82e08fc0c1f8eaa05b4bae87d5/httpx-0.27.0-py3-none-any.whl - sha256: 71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5 - requires_dist: - - anyio - - certifi - - httpcore ==1.* - - idna - - sniffio - - brotli ; platform_python_implementation == 'CPython' and extra == 'brotli' - - brotlicffi ; platform_python_implementation != 'CPython' and extra == 'brotli' - - click ==8.* ; extra == 'cli' - - pygments ==2.* ; extra == 'cli' - - rich <14, >=10 ; extra == 'cli' - - h2 <5, >=3 ; extra == 'http2' - - socksio ==1.* ; extra == 'socks' - requires_python: '>=3.8' -- kind: conda - name: icu - version: '73.2' - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/icu-73.2-h59595ed_0.conda - sha256: e12fd90ef6601da2875ebc432452590bc82a893041473bc1c13ef29001a73ea8 - md5: cc47e1facc155f91abd89b11e48e72ff - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: MIT - license_family: MIT - size: 12089150 - timestamp: 1692900650789 -- kind: conda - name: idna - version: '3.7' - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/idna-3.7-pyhd8ed1ab_0.conda - sha256: 9687ee909ed46169395d4f99a0ee94b80a52f87bed69cd454bb6d37ffeb0ec7b - md5: c0cc1420498b17414d8617d0b9f506ca - depends: - - python >=3.6 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/idna - size: 52718 - timestamp: 1713279497047 -- kind: pypi - name: imageio - version: 2.34.1 - url: https://files.pythonhosted.org/packages/a3/b6/39c7dad203d9984225f47e0aa39ac3ba3a47c77a02d0ef2a7be691855a06/imageio-2.34.1-py3-none-any.whl - sha256: 408c1d4d62f72c9e8347e7d1ca9bc11d8673328af3913868db3b828e28b40a4c - requires_dist: - - numpy - - pillow >=8.3.2 - - astropy ; extra == 'all-plugins' - - av ; extra == 'all-plugins' - - imageio-ffmpeg ; extra == 'all-plugins' - - pillow-heif ; extra == 'all-plugins' - - psutil ; extra == 'all-plugins' - - tifffile ; extra == 'all-plugins' - - av ; extra == 'all-plugins-pypy' - - imageio-ffmpeg ; extra == 'all-plugins-pypy' - - pillow-heif ; extra == 'all-plugins-pypy' - - psutil ; extra == 'all-plugins-pypy' - - tifffile ; extra == 'all-plugins-pypy' - - wheel ; extra == 'build' - - pytest ; extra == 'dev' - - pytest-cov ; extra == 'dev' - - fsspec[github] ; extra == 'dev' - - black ; extra == 'dev' - - flake8 ; extra == 'dev' - - sphinx <6 ; extra == 'docs' - - numpydoc ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - imageio-ffmpeg ; extra == 'ffmpeg' - - psutil ; extra == 'ffmpeg' - - astropy ; extra == 'fits' - - astropy ; extra == 'full' - - av ; extra == 'full' - - black ; extra == 'full' - - flake8 ; extra == 'full' - - fsspec[github] ; extra == 'full' - - gdal ; extra == 'full' - - imageio-ffmpeg ; extra == 'full' - - itk ; extra == 'full' - - numpydoc ; extra == 'full' - - pillow-heif ; extra == 'full' - - psutil ; extra == 'full' - - pydata-sphinx-theme ; extra == 'full' - - pytest ; extra == 'full' - - pytest-cov ; extra == 'full' - - sphinx <6 ; extra == 'full' - - tifffile ; extra == 'full' - - wheel ; extra == 'full' - - gdal ; extra == 'gdal' - - itk ; extra == 'itk' - - black ; extra == 'linting' - - flake8 ; extra == 'linting' - - pillow-heif ; extra == 'pillow-heif' - - av ; extra == 'pyav' - - pytest ; extra == 'test' - - pytest-cov ; extra == 'test' - - fsspec[github] ; extra == 'test' - - tifffile ; extra == 'tifffile' - requires_python: '>=3.8' -- kind: conda - name: imath - version: 3.1.11 - build: hfc55251_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/imath-3.1.11-hfc55251_0.conda - sha256: b394465d3c6a9c5b17351562a87df2a5ef541d66f1a2d95d80fe28c9ca7638c3 - md5: 07268e57799c7ad50809cadc297a515e - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: BSD-3-Clause - license_family: BSD - size: 162530 - timestamp: 1709194196768 -- kind: pypi - name: importlib-metadata - version: 7.1.0 - url: https://files.pythonhosted.org/packages/2d/0a/679461c511447ffaf176567d5c496d1de27cbe34a87df6677d7171b2fbd4/importlib_metadata-7.1.0-py3-none-any.whl - sha256: 30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570 - requires_dist: - - zipp >=0.5 - - typing-extensions >=3.6.4 ; python_version < '3.8' - - sphinx >=3.5 ; extra == 'docs' - - jaraco-packaging >=9.3 ; extra == 'docs' - - rst-linker >=1.9 ; extra == 'docs' - - furo ; extra == 'docs' - - sphinx-lint ; extra == 'docs' - - jaraco-tidelift >=1.4 ; extra == 'docs' - - ipython ; extra == 'perf' - - pytest >=6 ; extra == 'testing' - - pytest-checkdocs >=2.4 ; extra == 'testing' - - pytest-cov ; extra == 'testing' - - pytest-enabler >=2.2 ; extra == 'testing' - - pytest-ruff >=0.2.1 ; extra == 'testing' - - packaging ; extra == 'testing' - - pyfakefs ; extra == 'testing' - - flufl-flake8 ; extra == 'testing' - - pytest-perf >=0.9.2 ; extra == 'testing' - - jaraco-test >=5.4 ; extra == 'testing' - - pytest-mypy ; platform_python_implementation != 'PyPy' and extra == 'testing' - - importlib-resources >=1.3 ; python_version < '3.9' and extra == 'testing' - requires_python: '>=3.8' -- kind: pypi - name: ipykernel - version: 6.29.4 - url: https://files.pythonhosted.org/packages/53/9d/40d5207db523363d9b5698f33778c18b0d591e3fdb6e0116b894b2a2491c/ipykernel-6.29.4-py3-none-any.whl - sha256: 1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da - requires_dist: - - appnope ; platform_system == 'Darwin' - - comm >=0.1.1 - - debugpy >=1.6.5 - - ipython >=7.23.1 - - jupyter-client >=6.1.12 - - jupyter-core !=5.0.*, >=4.12 - - matplotlib-inline >=0.1 - - nest-asyncio - - packaging - - psutil - - pyzmq >=24 - - tornado >=6.1 - - traitlets >=5.4.0 - - coverage[toml] ; extra == 'cov' - - curio ; extra == 'cov' - - matplotlib ; extra == 'cov' - - pytest-cov ; extra == 'cov' - - trio ; extra == 'cov' - - myst-parser ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinx ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - sphinxcontrib-github-alt ; extra == 'docs' - - sphinxcontrib-spelling ; extra == 'docs' - - trio ; extra == 'docs' - - pyqt5 ; extra == 'pyqt5' - - pyside6 ; extra == 'pyside6' - - flaky ; extra == 'test' - - ipyparallel ; extra == 'test' - - pre-commit ; extra == 'test' - - pytest-asyncio >=0.23.5 ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest >=7.0 ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: ipython - version: 8.24.0 - url: https://files.pythonhosted.org/packages/71/1b/c7bbd3e03ee6f3580a8afbdf8d6fd38279da03bd5c4bc431907ea3246f9a/ipython-8.24.0-py3-none-any.whl - sha256: d7bf2f6c4314984e3e02393213bab8703cf163ede39672ce5918c51fe253a2a3 - requires_dist: - - decorator - - jedi >=0.16 - - matplotlib-inline - - prompt-toolkit <3.1.0, >=3.0.41 - - pygments >=2.4.0 - - stack-data - - traitlets >=5.13.0 - - exceptiongroup ; python_version < '3.11' - - typing-extensions >=4.6 ; python_version < '3.12' - - pexpect >4.3 ; sys_platform != 'win32' and sys_platform != 'emscripten' - - colorama ; sys_platform == 'win32' - - ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole] ; extra == 'all' - - ipython[test,test-extra] ; extra == 'all' - - black ; extra == 'black' - - ipykernel ; extra == 'doc' - - setuptools >=18.5 ; extra == 'doc' - - sphinx >=1.3 ; extra == 'doc' - - sphinx-rtd-theme ; extra == 'doc' - - sphinxcontrib-jquery ; extra == 'doc' - - docrepr ; extra == 'doc' - - matplotlib ; extra == 'doc' - - stack-data ; extra == 'doc' - - typing-extensions ; extra == 'doc' - - exceptiongroup ; extra == 'doc' - - ipython[test] ; extra == 'doc' - - ipykernel ; extra == 'kernel' - - matplotlib ; extra == 'matplotlib' - - nbconvert ; extra == 'nbconvert' - - nbformat ; extra == 'nbformat' - - ipywidgets ; extra == 'notebook' - - notebook ; extra == 'notebook' - - ipyparallel ; extra == 'parallel' - - qtconsole ; extra == 'qtconsole' - - pytest ; extra == 'test' - - pytest-asyncio <0.22 ; extra == 'test' - - testpath ; extra == 'test' - - pickleshare ; extra == 'test' - - ipython[test] ; extra == 'test_extra' - - curio ; extra == 'test_extra' - - matplotlib !=3.2.0 ; extra == 'test_extra' - - nbformat ; extra == 'test_extra' - - numpy >=1.23 ; extra == 'test_extra' - - pandas ; extra == 'test_extra' - - trio ; extra == 'test_extra' - requires_python: '>=3.10' -- kind: pypi - name: ipywidgets - version: 8.1.2 - url: https://files.pythonhosted.org/packages/70/1a/7edeedb1c089d63ccd8bd5c0612334774e90cf9337de9fe6c82d90081791/ipywidgets-8.1.2-py3-none-any.whl - sha256: bbe43850d79fb5e906b14801d6c01402857996864d1e5b6fa62dd2ee35559f60 - requires_dist: - - comm >=0.1.3 - - ipython >=6.1.0 - - traitlets >=4.3.1 - - widgetsnbextension ~=4.0.10 - - jupyterlab-widgets ~=3.0.10 - - jsonschema ; extra == 'test' - - ipykernel ; extra == 'test' - - pytest >=3.6.0 ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytz ; extra == 'test' - requires_python: '>=3.7' -- kind: pypi - name: isoduration - version: 20.11.0 - url: https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl - sha256: b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042 - requires_dist: - - arrow >=0.15.0 - requires_python: '>=3.7' -- kind: pypi - name: itsdangerous - version: 2.2.0 - url: https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl - sha256: c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef - requires_python: '>=3.8' -- kind: pypi - name: jaxtyping - version: 0.2.28 - url: https://files.pythonhosted.org/packages/9a/0c/8055b6e60e6b2795c1cee6058287c39f168466e5937d6437b58b6c7e77f7/jaxtyping-0.2.28-py3-none-any.whl - sha256: 4a54eb964087cd46463d9a86c805b4e4f5c20cce5f22049d6f35a26d9f105bd3 - requires_dist: - - numpy >=1.20.0 - - typeguard ==2.13.3 - requires_python: ~=3.9 -- kind: pypi - name: jedi - version: 0.19.1 - url: https://files.pythonhosted.org/packages/20/9f/bc63f0f0737ad7a60800bfd472a4836661adae21f9c2535f3957b1e54ceb/jedi-0.19.1-py2.py3-none-any.whl - sha256: e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0 - requires_dist: - - parso <0.9.0, >=0.8.3 - - jinja2 ==2.11.3 ; extra == 'docs' - - markupsafe ==1.1.1 ; extra == 'docs' - - pygments ==2.8.1 ; extra == 'docs' - - alabaster ==0.7.12 ; extra == 'docs' - - babel ==2.9.1 ; extra == 'docs' - - chardet ==4.0.0 ; extra == 'docs' - - commonmark ==0.8.1 ; extra == 'docs' - - docutils ==0.17.1 ; extra == 'docs' - - future ==0.18.2 ; extra == 'docs' - - idna ==2.10 ; extra == 'docs' - - imagesize ==1.2.0 ; extra == 'docs' - - mock ==1.0.1 ; extra == 'docs' - - packaging ==20.9 ; extra == 'docs' - - pyparsing ==2.4.7 ; extra == 'docs' - - pytz ==2021.1 ; extra == 'docs' - - readthedocs-sphinx-ext ==2.1.4 ; extra == 'docs' - - recommonmark ==0.5.0 ; extra == 'docs' - - requests ==2.25.1 ; extra == 'docs' - - six ==1.15.0 ; extra == 'docs' - - snowballstemmer ==2.1.0 ; extra == 'docs' - - sphinx-rtd-theme ==0.4.3 ; extra == 'docs' - - sphinx ==1.8.5 ; extra == 'docs' - - sphinxcontrib-serializinghtml ==1.1.4 ; extra == 'docs' - - sphinxcontrib-websupport ==1.2.4 ; extra == 'docs' - - urllib3 ==1.26.4 ; extra == 'docs' - - flake8 ==5.0.4 ; extra == 'qa' - - mypy ==0.971 ; extra == 'qa' - - types-setuptools ==67.2.0.1 ; extra == 'qa' - - django ; extra == 'testing' - - attrs ; extra == 'testing' - - colorama ; extra == 'testing' - - docopt ; extra == 'testing' - - pytest <7.0.0 ; extra == 'testing' - requires_python: '>=3.6' -- kind: conda - name: jinja2 - version: 3.1.4 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.4-pyhd8ed1ab_0.conda - sha256: 27380d870d42d00350d2d52598cddaf02f9505fb24be09488da0c9b8d1428f2d - md5: 7b86ecb7d3557821c649b3c31e3eb9f2 - depends: - - markupsafe >=2.0 - - python >=3.7 - license: BSD-3-Clause - purls: - - pkg:pypi/jinja2 - size: 111565 - timestamp: 1715127275924 -- kind: pypi - name: jmespath - version: 1.0.1 - url: https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl - sha256: 02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980 - requires_python: '>=3.7' -- kind: pypi - name: joblib - version: 1.4.2 - url: https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl - sha256: 06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6 - requires_python: '>=3.8' -- kind: pypi - name: json5 - version: 0.9.25 - url: https://files.pythonhosted.org/packages/8a/3c/4f8791ee53ab9eeb0b022205aa79387119a74cc9429582ce04098e6fc540/json5-0.9.25-py3-none-any.whl - sha256: 34ed7d834b1341a86987ed52f3f76cd8ee184394906b6e22a1e0deb9ab294e8f - requires_python: '>=3.8' -- kind: pypi - name: jsonpointer - version: '2.4' - url: https://files.pythonhosted.org/packages/12/f6/0232cc0c617e195f06f810534d00b74d2f348fe71b2118009ad8ad31f878/jsonpointer-2.4-py2.py3-none-any.whl - sha256: 15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*' -- kind: pypi - name: jsonschema - version: 4.22.0 - url: https://files.pythonhosted.org/packages/c8/2f/324fab4be6fe37fb7b521546e8a557e6cf08c1c1b3d0b4839a00f589d9ef/jsonschema-4.22.0-py3-none-any.whl - sha256: ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802 - requires_dist: - - attrs >=22.2.0 - - importlib-resources >=1.4.0 ; python_version < '3.9' - - jsonschema-specifications >=2023.3.6 - - pkgutil-resolve-name >=1.3.10 ; python_version < '3.9' - - referencing >=0.28.4 - - rpds-py >=0.7.1 - - fqdn ; extra == 'format' - - idna ; extra == 'format' - - isoduration ; extra == 'format' - - jsonpointer >1.13 ; extra == 'format' - - rfc3339-validator ; extra == 'format' - - rfc3987 ; extra == 'format' - - uri-template ; extra == 'format' - - webcolors >=1.11 ; extra == 'format' - - fqdn ; extra == 'format-nongpl' - - idna ; extra == 'format-nongpl' - - isoduration ; extra == 'format-nongpl' - - jsonpointer >1.13 ; extra == 'format-nongpl' - - rfc3339-validator ; extra == 'format-nongpl' - - rfc3986-validator >0.1.0 ; extra == 'format-nongpl' - - uri-template ; extra == 'format-nongpl' - - webcolors >=1.11 ; extra == 'format-nongpl' - requires_python: '>=3.8' -- kind: pypi - name: jsonschema-specifications - version: 2023.12.1 - url: https://files.pythonhosted.org/packages/ee/07/44bd408781594c4d0a027666ef27fab1e441b109dc3b76b4f836f8fd04fe/jsonschema_specifications-2023.12.1-py3-none-any.whl - sha256: 87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c - requires_dist: - - importlib-resources >=1.4.0 ; python_version < '3.9' - - referencing >=0.31.0 - requires_python: '>=3.8' -- kind: pypi - name: jupyter - version: 1.0.0 - url: https://files.pythonhosted.org/packages/83/df/0f5dd132200728a86190397e1ea87cd76244e42d39ec5e88efd25b2abd7e/jupyter-1.0.0-py2.py3-none-any.whl - sha256: 5b290f93b98ffbc21c0c7e749f054b3267782166d72fa5e3ed1ed4eaf34a2b78 - requires_dist: - - notebook - - qtconsole - - jupyter-console - - nbconvert - - ipykernel - - ipywidgets -- kind: pypi - name: jupyter-client - version: 8.6.1 - url: https://files.pythonhosted.org/packages/75/6d/d7b55b9c1ac802ab066b3e5015e90faab1fffbbd67a2af498ffc6cc81c97/jupyter_client-8.6.1-py3-none-any.whl - sha256: 3b7bd22f058434e3b9a7ea4b1500ed47de2713872288c0d511d19926f99b459f - requires_dist: - - importlib-metadata >=4.8.3 ; python_version < '3.10' - - jupyter-core !=5.0.*, >=4.12 - - python-dateutil >=2.8.2 - - pyzmq >=23.0 - - tornado >=6.2 - - traitlets >=5.3 - - ipykernel ; extra == 'docs' - - myst-parser ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - sphinx >=4 ; extra == 'docs' - - sphinxcontrib-github-alt ; extra == 'docs' - - sphinxcontrib-spelling ; extra == 'docs' - - coverage ; extra == 'test' - - ipykernel >=6.14 ; extra == 'test' - - mypy ; extra == 'test' - - paramiko ; sys_platform == 'win32' and extra == 'test' - - pre-commit ; extra == 'test' - - pytest ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-jupyter[client] >=0.4.1 ; extra == 'test' - - pytest-timeout ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: jupyter-console - version: 6.6.3 - url: https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl - sha256: 309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485 - requires_dist: - - ipykernel >=6.14 - - ipython - - jupyter-client >=7.0.0 - - jupyter-core !=5.0.*, >=4.12 - - prompt-toolkit >=3.0.30 - - pygments - - pyzmq >=17 - - traitlets >=5.4 - - flaky ; extra == 'test' - - pexpect ; extra == 'test' - - pytest ; extra == 'test' - requires_python: '>=3.7' -- kind: pypi - name: jupyter-core - version: 5.7.2 - url: https://files.pythonhosted.org/packages/c9/fb/108ecd1fe961941959ad0ee4e12ee7b8b1477247f30b1fdfd83ceaf017f0/jupyter_core-5.7.2-py3-none-any.whl - sha256: 4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409 - requires_dist: - - platformdirs >=2.5 - - pywin32 >=300 ; sys_platform == 'win32' and platform_python_implementation != 'PyPy' - - traitlets >=5.3 - - myst-parser ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - sphinxcontrib-github-alt ; extra == 'docs' - - sphinxcontrib-spelling ; extra == 'docs' - - traitlets ; extra == 'docs' - - ipykernel ; extra == 'test' - - pre-commit ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest <8 ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: jupyter-events - version: 0.10.0 - url: https://files.pythonhosted.org/packages/a5/94/059180ea70a9a326e1815176b2370da56376da347a796f8c4f0b830208ef/jupyter_events-0.10.0-py3-none-any.whl - sha256: 4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960 - requires_dist: - - jsonschema[format-nongpl] >=4.18.0 - - python-json-logger >=2.0.4 - - pyyaml >=5.3 - - referencing - - rfc3339-validator - - rfc3986-validator >=0.1.1 - - traitlets >=5.3 - - click ; extra == 'cli' - - rich ; extra == 'cli' - - jupyterlite-sphinx ; extra == 'docs' - - myst-parser ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinxcontrib-spelling ; extra == 'docs' - - click ; extra == 'test' - - pre-commit ; extra == 'test' - - pytest-asyncio >=0.19.0 ; extra == 'test' - - pytest-console-scripts ; extra == 'test' - - pytest >=7.0 ; extra == 'test' - - rich ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: jupyter-lsp - version: 2.2.5 - url: https://files.pythonhosted.org/packages/07/e0/7bd7cff65594fd9936e2f9385701e44574fc7d721331ff676ce440b14100/jupyter_lsp-2.2.5-py3-none-any.whl - sha256: 45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da - requires_dist: - - jupyter-server >=1.1.2 - - importlib-metadata >=4.8.3 ; python_version < '3.10' - requires_python: '>=3.8' -- kind: pypi - name: jupyter-server - version: 2.13.0 - url: https://files.pythonhosted.org/packages/95/85/483b8e09a897d1bc2194646d30d4ce6ae166106e91ecbd11d6b6d9ccfc36/jupyter_server-2.13.0-py3-none-any.whl - sha256: 77b2b49c3831fbbfbdb5048cef4350d12946191f833a24e5f83e5f8f4803e97b - requires_dist: - - anyio >=3.1.0 - - argon2-cffi - - jinja2 - - jupyter-client >=7.4.4 - - jupyter-core !=5.0.*, >=4.12 - - jupyter-events >=0.9.0 - - jupyter-server-terminals - - nbconvert >=6.4.4 - - nbformat >=5.3.0 - - overrides - - packaging - - prometheus-client - - pywinpty ; os_name == 'nt' - - pyzmq >=24 - - send2trash >=1.8.2 - - terminado >=0.8.3 - - tornado >=6.2.0 - - traitlets >=5.6.0 - - websocket-client - - ipykernel ; extra == 'docs' - - jinja2 ; extra == 'docs' - - jupyter-client ; extra == 'docs' - - jupyter-server ; extra == 'docs' - - myst-parser ; extra == 'docs' - - nbformat ; extra == 'docs' - - prometheus-client ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - send2trash ; extra == 'docs' - - sphinx-autodoc-typehints ; extra == 'docs' - - sphinxcontrib-github-alt ; extra == 'docs' - - sphinxcontrib-openapi >=0.8.0 ; extra == 'docs' - - sphinxcontrib-spelling ; extra == 'docs' - - sphinxemoji ; extra == 'docs' - - tornado ; extra == 'docs' - - typing-extensions ; extra == 'docs' - - flaky ; extra == 'test' - - ipykernel ; extra == 'test' - - pre-commit ; extra == 'test' - - pytest-console-scripts ; extra == 'test' - - pytest-jupyter[server] >=0.7 ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest >=7.0 ; extra == 'test' - - requests ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: jupyter-server-terminals - version: 0.5.3 - url: https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl - sha256: 41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa - requires_dist: - - pywinpty >=2.0.3 ; os_name == 'nt' - - terminado >=0.8.3 - - jinja2 ; extra == 'docs' - - jupyter-server ; extra == 'docs' - - mistune <4.0 ; extra == 'docs' - - myst-parser ; extra == 'docs' - - nbformat ; extra == 'docs' - - packaging ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinxcontrib-github-alt ; extra == 'docs' - - sphinxcontrib-openapi ; extra == 'docs' - - sphinxcontrib-spelling ; extra == 'docs' - - sphinxemoji ; extra == 'docs' - - tornado ; extra == 'docs' - - jupyter-server >=2.0.0 ; extra == 'test' - - pytest-jupyter[server] >=0.5.3 ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest >=7.0 ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: jupyterlab - version: 4.2.0 - url: https://files.pythonhosted.org/packages/72/c3/532326adbb2b76f709e3e582aeefd0a85bd7454599ff450d90dd9540f5ed/jupyterlab-4.2.0-py3-none-any.whl - sha256: 0dfe9278e25a145362289c555d9beb505697d269c10e99909766af7c440ad3cc - requires_dist: - - async-lru >=1.0.0 - - httpx >=0.25.0 - - importlib-metadata >=4.8.3 ; python_version < '3.10' - - importlib-resources >=1.4 ; python_version < '3.9' - - ipykernel >=6.5.0 - - jinja2 >=3.0.3 - - jupyter-core - - jupyter-lsp >=2.0.0 - - jupyter-server <3, >=2.4.0 - - jupyterlab-server <3, >=2.27.1 - - notebook-shim >=0.2 - - packaging - - tomli >=1.2.2 ; python_version < '3.11' - - tornado >=6.2.0 - - traitlets - - build ; extra == 'dev' - - bump2version ; extra == 'dev' - - coverage ; extra == 'dev' - - hatch ; extra == 'dev' - - pre-commit ; extra == 'dev' - - pytest-cov ; extra == 'dev' - - ruff ==0.3.5 ; extra == 'dev' - - jsx-lexer ; extra == 'docs' - - myst-parser ; extra == 'docs' - - pydata-sphinx-theme >=0.13.0 ; extra == 'docs' - - pytest ; extra == 'docs' - - pytest-check-links ; extra == 'docs' - - pytest-jupyter ; extra == 'docs' - - sphinx-copybutton ; extra == 'docs' - - sphinx <7.3.0, >=1.8 ; extra == 'docs' - - altair ==5.3.0 ; extra == 'docs-screenshots' - - ipython ==8.16.1 ; extra == 'docs-screenshots' - - ipywidgets ==8.1.2 ; extra == 'docs-screenshots' - - jupyterlab-geojson ==3.4.0 ; extra == 'docs-screenshots' - - jupyterlab-language-pack-zh-cn ==4.1.post2 ; extra == 'docs-screenshots' - - matplotlib ==3.8.3 ; extra == 'docs-screenshots' - - nbconvert >=7.0.0 ; extra == 'docs-screenshots' - - pandas ==2.2.1 ; extra == 'docs-screenshots' - - scipy ==1.12.0 ; extra == 'docs-screenshots' - - vega-datasets ==0.9.0 ; extra == 'docs-screenshots' - - coverage ; extra == 'test' - - pytest-check-links >=0.7 ; extra == 'test' - - pytest-console-scripts ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-jupyter >=0.5.3 ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest-tornasync ; extra == 'test' - - pytest >=7.0 ; extra == 'test' - - requests ; extra == 'test' - - requests-cache ; extra == 'test' - - virtualenv ; extra == 'test' - - copier <10, >=8 ; extra == 'upgrade-extension' - - jinja2-time <0.3 ; extra == 'upgrade-extension' - - pydantic <2.0 ; extra == 'upgrade-extension' - - pyyaml-include <2.0 ; extra == 'upgrade-extension' - - tomli-w <2.0 ; extra == 'upgrade-extension' - requires_python: '>=3.8' -- kind: pypi - name: jupyterlab-pygments - version: 0.3.0 - url: https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl - sha256: 841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780 - requires_python: '>=3.8' -- kind: pypi - name: jupyterlab-server - version: 2.27.1 - url: https://files.pythonhosted.org/packages/2f/b9/ed4ecad7cf1863a64920dc4c19b0376628b5d6bd28d2ec1e00cbac4ba2fb/jupyterlab_server-2.27.1-py3-none-any.whl - sha256: f5e26156e5258b24d532c84e7c74cc212e203bff93eb856f81c24c16daeecc75 - requires_dist: - - babel >=2.10 - - importlib-metadata >=4.8.3 ; python_version < '3.10' - - jinja2 >=3.0.3 - - json5 >=0.9.0 - - jsonschema >=4.18.0 - - jupyter-server <3, >=1.21 - - packaging >=21.3 - - requests >=2.31 - - autodoc-traits ; extra == 'docs' - - jinja2 <3.2.0 ; extra == 'docs' - - mistune <4 ; extra == 'docs' - - myst-parser ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinx ; extra == 'docs' - - sphinx-copybutton ; extra == 'docs' - - sphinxcontrib-openapi >0.8 ; extra == 'docs' - - openapi-core ~=0.18.0 ; extra == 'openapi' - - ruamel-yaml ; extra == 'openapi' - - hatch ; extra == 'test' - - ipykernel ; extra == 'test' - - openapi-core ~=0.18.0 ; extra == 'test' - - openapi-spec-validator <0.8.0, >=0.6.0 ; extra == 'test' - - pytest-console-scripts ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-jupyter[server] >=0.6.2 ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest <8, >=7.0 ; extra == 'test' - - requests-mock ; extra == 'test' - - ruamel-yaml ; extra == 'test' - - sphinxcontrib-spelling ; extra == 'test' - - strict-rfc3339 ; extra == 'test' - - werkzeug ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: jupyterlab-widgets - version: 3.0.10 - url: https://files.pythonhosted.org/packages/24/da/db1cb0387a7e4086780aff137987ee924e953d7f91b2a870f994b9b1eeb8/jupyterlab_widgets-3.0.10-py3-none-any.whl - sha256: dd61f3ae7a5a7f80299e14585ce6cf3d6925a96c9103c978eda293197730cb64 - requires_python: '>=3.7' -- kind: conda - name: jxrlib - version: '1.1' - build: hd590300_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-hd590300_3.conda - sha256: 2057ca87b313bde5b74b93b0e696f8faab69acd4cb0edebb78469f3f388040c0 - md5: 5aeabe88534ea4169d4c49998f293d6c - depends: - - libgcc-ng >=12 - license: BSD-2-Clause - license_family: BSD - size: 239104 - timestamp: 1703333860145 -- kind: conda - name: keyutils - version: 1.6.1 - build: h166bdaf_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.1-h166bdaf_0.tar.bz2 - sha256: 150c05a6e538610ca7c43beb3a40d65c90537497a4f6a5f4d15ec0451b6f5ebb - md5: 30186d27e2c9fa62b45fb1476b7200e3 - depends: - - libgcc-ng >=10.3.0 - license: LGPL-2.1-or-later - size: 117831 - timestamp: 1646151697040 -- kind: pypi - name: kiwisolver - version: 1.4.5 - url: https://files.pythonhosted.org/packages/6f/40/4ab1fdb57fced80ce5903f04ae1aed7c1d5939dda4fd0c0aa526c12fe28a/kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl - sha256: ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff - requires_dist: - - typing-extensions ; python_version < '3.8' - requires_python: '>=3.7' -- kind: conda - name: krb5 - version: 1.21.2 - build: h659d440_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/krb5-1.21.2-h659d440_0.conda - sha256: 259bfaae731989b252b7d2228c1330ef91b641c9d68ff87dae02cbae682cb3e4 - md5: cd95826dbd331ed1be26bdf401432844 - depends: - - keyutils >=1.6.1,<2.0a0 - - libedit >=3.1.20191231,<3.2.0a0 - - libedit >=3.1.20191231,<4.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - openssl >=3.1.2,<4.0a0 - license: MIT - license_family: MIT - size: 1371181 - timestamp: 1692097755782 -- kind: conda - name: lame - version: '3.100' - build: h166bdaf_1003 - build_number: 1003 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/lame-3.100-h166bdaf_1003.tar.bz2 - sha256: aad2a703b9d7b038c0f745b853c6bb5f122988fe1a7a096e0e606d9cbec4eaab - md5: a8832b479f93521a9e7b5b743803be51 - depends: - - libgcc-ng >=12 - license: LGPL-2.0-only - license_family: LGPL - size: 508258 - timestamp: 1664996250081 -- kind: pypi - name: lazy-loader - version: '0.4' - url: https://files.pythonhosted.org/packages/83/60/d497a310bde3f01cb805196ac61b7ad6dc5dcf8dce66634dc34364b20b4f/lazy_loader-0.4-py3-none-any.whl - sha256: 342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc - requires_dist: - - packaging - - importlib-metadata ; python_version < '3.8' - - changelist ==0.5 ; extra == 'dev' - - pre-commit ==3.7.0 ; extra == 'lint' - - pytest >=7.4 ; extra == 'test' - - pytest-cov >=4.1 ; extra == 'test' - requires_python: '>=3.7' -- kind: conda - name: lcms2 - version: '2.16' - build: hb7c19ff_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.16-hb7c19ff_0.conda - sha256: 5c878d104b461b7ef922abe6320711c0d01772f4cd55de18b674f88547870041 - md5: 51bb7010fc86f70eee639b4bb7a894f5 - depends: - - libgcc-ng >=12 - - libjpeg-turbo >=3.0.0,<4.0a0 - - libtiff >=4.6.0,<4.7.0a0 - license: MIT - license_family: MIT - size: 245247 - timestamp: 1701647787198 -- kind: conda - name: ld_impl_linux-64 - version: '2.40' - build: h55db66e_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h55db66e_0.conda - sha256: ef969eee228cfb71e55146eaecc6af065f468cb0bc0a5239bc053b39db0b5f09 - md5: 10569984e7db886e4f1abc2b47ad79a1 - constrains: - - binutils_impl_linux-64 2.40 - license: GPL-3.0-only - license_family: GPL - size: 713322 - timestamp: 1713651222435 -- kind: conda - name: lerc - version: 4.0.0 - build: h27087fc_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/lerc-4.0.0-h27087fc_0.tar.bz2 - sha256: cb55f36dcd898203927133280ae1dc643368af041a48bcf7c026acb7c47b0c12 - md5: 76bbff344f0134279f225174e9064c8f - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: Apache-2.0 - license_family: Apache - size: 281798 - timestamp: 1657977462600 -- kind: conda - name: libabseil - version: '20240116.2' - build: cxx17_h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libabseil-20240116.2-cxx17_h59595ed_0.conda - sha256: 19b789dc38dff64eee2002675991e63f381eedf5efd5c85f2dac512ed97376d7 - md5: 682bdbe046a68f749769b492f3625c5c - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - constrains: - - libabseil-static =20240116.2=cxx17* - - abseil-cpp =20240116.2 - license: Apache-2.0 - license_family: Apache - size: 1266634 - timestamp: 1714403128134 -- kind: conda - name: libaec - version: 1.1.3 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.3-h59595ed_0.conda - sha256: 2ef420a655528bca9d269086cf33b7e90d2f54ad941b437fb1ed5eca87cee017 - md5: 5e97e271911b8b2001a8b71860c32faa - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: BSD-2-Clause - license_family: BSD - size: 35446 - timestamp: 1711021212685 -- kind: conda - name: libarrow - version: 15.0.2 - build: hefa796f_6_cpu - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libarrow-15.0.2-hefa796f_6_cpu.conda - sha256: d97be4671bc6a76c177a8611677f46fbd9f30227c73b2d26bd8276df4385bf21 - md5: 2aa703494b2c0a1356ec581a24653177 - depends: - - aws-crt-cpp >=0.26.8,<0.26.9.0a0 - - aws-sdk-cpp >=1.11.267,<1.11.268.0a0 - - bzip2 >=1.0.8,<2.0a0 - - gflags >=2.2.2,<2.3.0a0 - - glog >=0.7.0,<0.8.0a0 - - libabseil * cxx17* - - libabseil >=20240116.2,<20240117.0a0 - - libbrotlidec >=1.1.0,<1.2.0a0 - - libbrotlienc >=1.1.0,<1.2.0a0 - - libgcc-ng >=12 - - libgoogle-cloud >=2.23.0,<2.24.0a0 - - libgoogle-cloud-storage >=2.23.0,<2.24.0a0 - - libre2-11 >=2023.9.1,<2024.0a0 - - libstdcxx-ng >=12 - - libutf8proc >=2.8.0,<3.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - lz4-c >=1.9.3,<1.10.0a0 - - orc >=2.0.0,<2.0.1.0a0 - - re2 - - snappy >=1.2.0,<1.3.0a0 - - zstd >=1.5.5,<1.6.0a0 - constrains: - - arrow-cpp <0.0a0 - - apache-arrow-proc =*=cpu - - parquet-cpp <0.0a0 - license: Apache-2.0 - license_family: APACHE - size: 8174304 - timestamp: 1714448169194 -- kind: conda - name: libarrow-acero - version: 15.0.2 - build: hbabe93e_6_cpu - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libarrow-acero-15.0.2-hbabe93e_6_cpu.conda - sha256: 75e88940751abc5b48fc44721e36fcddd7dd5c5bc1d8622ed36fc1c93b26beb1 - md5: 061797e461211bbdc174fdabeb45ac5c - depends: - - gflags >=2.2.2,<2.3.0a0 - - libarrow 15.0.2 hefa796f_6_cpu - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: Apache-2.0 - license_family: APACHE - size: 600779 - timestamp: 1714448211788 -- kind: conda - name: libarrow-dataset - version: 15.0.2 - build: hbabe93e_6_cpu - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libarrow-dataset-15.0.2-hbabe93e_6_cpu.conda - sha256: 9611a2a415523d5b5533036a73af72deb621f68e1a6cd3bcd0572aceed2a9b4e - md5: f30638c82fb4ce663122a3714ef0aa7d - depends: - - gflags >=2.2.2,<2.3.0a0 - - libarrow 15.0.2 hefa796f_6_cpu - - libarrow-acero 15.0.2 hbabe93e_6_cpu - - libgcc-ng >=12 - - libparquet 15.0.2 hacf5a1f_6_cpu - - libstdcxx-ng >=12 - license: Apache-2.0 - license_family: APACHE - size: 587827 - timestamp: 1714448297550 -- kind: conda - name: libarrow-flight - version: 15.0.2 - build: hc4f8a93_6_cpu - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libarrow-flight-15.0.2-hc4f8a93_6_cpu.conda - sha256: b75bfae411b8de65f3ccddf8acec2811d79b21b8da00788b4c8d279616d488e9 - md5: 5fb64b8a0a7b68e48a08cc138d3650b6 - depends: - - gflags >=2.2.2,<2.3.0a0 - - libabseil * cxx17* - - libabseil >=20240116.2,<20240117.0a0 - - libarrow 15.0.2 hefa796f_6_cpu - - libgcc-ng >=12 - - libgrpc >=1.62.2,<1.63.0a0 - - libprotobuf >=4.25.3,<4.25.4.0a0 - - libstdcxx-ng >=12 - - ucx >=1.15.0,<1.16.0a0 - license: Apache-2.0 - license_family: APACHE - size: 508666 - timestamp: 1714448232421 -- kind: conda - name: libarrow-flight-sql - version: 15.0.2 - build: he4f5ca8_6_cpu - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libarrow-flight-sql-15.0.2-he4f5ca8_6_cpu.conda - sha256: 761fceb170e0efee8f8c365f17ec706fab12a8e9378d3e80b36ed06b9390cb9b - md5: 2cd07c4ead6fb6bd1a2741c2a1cb5666 - depends: - - gflags >=2.2.2,<2.3.0a0 - - libarrow 15.0.2 hefa796f_6_cpu - - libarrow-flight 15.0.2 hc4f8a93_6_cpu - - libgcc-ng >=12 - - libprotobuf >=4.25.3,<4.25.4.0a0 - - libstdcxx-ng >=12 - license: Apache-2.0 - license_family: APACHE - size: 197489 - timestamp: 1714448319450 -- kind: conda - name: libarrow-gandiva - version: 15.0.2 - build: hc1954e9_6_cpu - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libarrow-gandiva-15.0.2-hc1954e9_6_cpu.conda - sha256: eb9ac1a92a60ddc23e34d007d6d73c095f0edd82f83fd63f7a29436e6c8c74f7 - md5: 80201ecc7f27bd6a2b50b8a7ee3f315f - depends: - - gflags >=2.2.2,<2.3.0a0 - - libarrow 15.0.2 hefa796f_6_cpu - - libgcc-ng >=12 - - libllvm16 >=16.0.6,<16.1.0a0 - - libre2-11 >=2023.9.1,<2024.0a0 - - libstdcxx-ng >=12 - - libutf8proc >=2.8.0,<3.0a0 - - openssl >=3.2.1,<4.0a0 - - re2 - license: Apache-2.0 - license_family: APACHE - size: 897964 - timestamp: 1714448255 -- kind: conda - name: libarrow-substrait - version: 15.0.2 - build: he4f5ca8_6_cpu - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libarrow-substrait-15.0.2-he4f5ca8_6_cpu.conda - sha256: 7ec84b1a2ed461184bf3c53304e61468765a2b2151d9522f3f9fac0612808249 - md5: cf594f6982de20afedf7aeb6602ceb89 - depends: - - gflags >=2.2.2,<2.3.0a0 - - libarrow 15.0.2 hefa796f_6_cpu - - libarrow-acero 15.0.2 hbabe93e_6_cpu - - libarrow-dataset 15.0.2 hbabe93e_6_cpu - - libgcc-ng >=12 - - libprotobuf >=4.25.3,<4.25.4.0a0 - - libstdcxx-ng >=12 - license: Apache-2.0 - license_family: APACHE - size: 521452 - timestamp: 1714448338650 -- kind: conda - name: libasprintf - version: 0.22.5 - build: h661eb56_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libasprintf-0.22.5-h661eb56_2.conda - sha256: 31d58af7eb54e2938123200239277f14893c5fa4b5d0280c8cf55ae10000638b - md5: dd197c968bf9760bba0031888d431ede - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: LGPL-2.1-or-later - size: 43226 - timestamp: 1712512265295 -- kind: conda - name: libasprintf-devel - version: 0.22.5 - build: h661eb56_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libasprintf-devel-0.22.5-h661eb56_2.conda - sha256: 99d26d272a8203d30b3efbe734a99c823499884d7759b4291674438137c4b5ca - md5: 02e41ab5834dcdcc8590cf29d9526f50 - depends: - - libasprintf 0.22.5 h661eb56_2 - - libgcc-ng >=12 - license: LGPL-2.1-or-later - size: 34225 - timestamp: 1712512295117 -- kind: conda - name: libass - version: 0.17.1 - build: h8fe9dca_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libass-0.17.1-h8fe9dca_1.conda - sha256: 1bc3e44239a11613627488b7a9b6c021ec6b52c5925abd666832db0cb2a59f05 - md5: c306fd9cc90c0585171167d09135a827 - depends: - - fontconfig >=2.14.2,<3.0a0 - - fonts-conda-ecosystem - - freetype >=2.12.1,<3.0a0 - - fribidi >=1.0.10,<2.0a0 - - harfbuzz >=8.1.1,<9.0a0 - - libexpat >=2.5.0,<3.0a0 - - libgcc-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: ISC - license_family: OTHER - size: 126896 - timestamp: 1693027051367 -- kind: conda - name: libblas - version: 3.9.0 - build: 1_h86c2bf4_netlib - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-1_h86c2bf4_netlib.tar.bz2 - sha256: c95bf82fbf258350d5f61c653a1a14d2e1cca7302bb348cc8347caa84e7ac9b1 - md5: 91273b91f1023d5c72ffc79e02e7812e - depends: - - libgcc-ng >=9.3.0 - - libgfortran-ng - - libgfortran5 >=9.3.0 - track_features: - - blas_netlib - license: BSD-3-Clause - license_family: BSD - size: 203305 - timestamp: 1603052017387 -- kind: conda - name: libboost - version: 1.84.0 - build: h8013b2b_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libboost-1.84.0-h8013b2b_2.conda - sha256: f38191766b87bbf4099851d40ecc17c5d6cf4f898b76a8d8648a5caaf04bf2da - md5: 2de948e2fa2aea5f2b23cd02edcba24a - depends: - - bzip2 >=1.0.8,<2.0a0 - - icu >=73.2,<74.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - xz >=5.2.6,<6.0a0 - - zstd >=1.5.5,<1.6.0a0 - constrains: - - boost-cpp =1.84.0 - license: BSL-1.0 - size: 2790076 - timestamp: 1711404148144 -- kind: conda - name: libbrotlicommon - version: 1.1.0 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.1.0-hd590300_1.conda - sha256: 40f29d1fab92c847b083739af86ad2f36d8154008cf99b64194e4705a1725d78 - md5: aec6c91c7371c26392a06708a73c70e5 - depends: - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 69403 - timestamp: 1695990007212 -- kind: conda - name: libbrotlidec - version: 1.1.0 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.1.0-hd590300_1.conda - sha256: 86fc861246fbe5ad85c1b6b3882aaffc89590a48b42d794d3d5c8e6d99e5f926 - md5: f07002e225d7a60a694d42a7bf5ff53f - depends: - - libbrotlicommon 1.1.0 hd590300_1 - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 32775 - timestamp: 1695990022788 -- kind: conda - name: libbrotlienc - version: 1.1.0 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.1.0-hd590300_1.conda - sha256: f751b8b1c4754a2a8dfdc3b4040fa7818f35bbf6b10e905a47d3a194b746b071 - md5: 5fc11c6020d421960607d821310fcd4d - depends: - - libbrotlicommon 1.1.0 hd590300_1 - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 282523 - timestamp: 1695990038302 -- kind: conda - name: libcap - version: '2.69' - build: h0f662aa_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libcap-2.69-h0f662aa_0.conda - sha256: 942f9564b4228609f017b6617425d29a74c43b8a030e12239fa4458e5cb6323c - md5: 25cb5999faa414e5ccb2c1388f62d3d5 - depends: - - attr >=2.5.1,<2.6.0a0 - - libgcc-ng >=12 - license: BSD-3-Clause - license_family: BSD - size: 100582 - timestamp: 1684162447012 -- kind: conda - name: libcblas - version: 3.9.0 - build: 5_h92ddd45_netlib - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.9.0-5_h92ddd45_netlib.tar.bz2 - sha256: 93086c3586c5b1f961cb468995dc35d9b99ca8f10d0b76d594a554029f60670c - md5: 6a3f536ec30f6e6948211a07b1d04ced - depends: - - libblas 3.9.0.* - - libgcc-ng >=9.3.0 - - libgfortran-ng - - libgfortran5 >=9.3.0 - track_features: - - blas_netlib - license: BSD-3-Clause - license_family: BSD - size: 55516 - timestamp: 1618011709500 -- kind: conda - name: libclang-cpp15 - version: 15.0.7 - build: default_h127d8a8_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libclang-cpp15-15.0.7-default_h127d8a8_5.conda - sha256: 9b0238e705a33da74ca82efd03974f499550f7dada1340cc9cb7c35a92411ed8 - md5: d0a9633b53cdc319b8a1a532ae7822b8 - depends: - - libgcc-ng >=12 - - libllvm15 >=15.0.7,<15.1.0a0 - - libstdcxx-ng >=12 - license: Apache-2.0 WITH LLVM-exception - license_family: Apache - size: 17206402 - timestamp: 1711063711931 -- kind: conda - name: libclang13 - version: 18.1.5 - build: default_h5d6823c_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libclang13-18.1.5-default_h5d6823c_0.conda - sha256: 60c7cdd313566033910bce884b879f39468eb966b2ac61ea828fe432b8a084c5 - md5: 60c39a00b694c98da03f67a3ba1d7499 - depends: - - libgcc-ng >=12 - - libllvm18 >=18.1.5,<18.2.0a0 - - libstdcxx-ng >=12 - license: Apache-2.0 WITH LLVM-exception - license_family: Apache - size: 11052898 - timestamp: 1714870310416 -- kind: conda - name: libcrc32c - version: 1.1.2 - build: h9c3ff4c_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2 - sha256: fd1d153962764433fe6233f34a72cdeed5dcf8a883a85769e8295ce940b5b0c5 - md5: c965a5aa0d5c1c37ffc62dff36e28400 - depends: - - libgcc-ng >=9.4.0 - - libstdcxx-ng >=9.4.0 - license: BSD-3-Clause - license_family: BSD - size: 20440 - timestamp: 1633683576494 -- kind: conda - name: libcublas - version: 11.11.3.6 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcublas-11.11.3.6-0.tar.bz2 - md5: 7700a48c99151d2b77e7838aa0852da9 - arch: x86_64 - platform: linux - size: 381637889 - timestamp: 1662499145253 -- kind: conda - name: libcublas-dev - version: 11.11.3.6 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcublas-dev-11.11.3.6-0.tar.bz2 - md5: d2097d064d1437dbbcce39c3e8018a4e - depends: - - libcublas >=11.11.3.6 - arch: x86_64 - platform: linux - size: 413253930 - timestamp: 1662499317965 -- kind: conda - name: libcufft - version: 10.9.0.58 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcufft-10.9.0.58-0.tar.bz2 - md5: dbb21687334ce5f8e6a233cb18ee406b - arch: x86_64 - platform: linux - size: 149741913 - timestamp: 1661545628099 -- kind: conda - name: libcufft-dev - version: 10.9.0.58 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcufft-dev-10.9.0.58-0.tar.bz2 - md5: bd0ef1722efed6b4d689043a1bbd72fc - depends: - - libcufft >=10.9.0.58 - arch: x86_64 - platform: linux - size: 289240757 - timestamp: 1661545712353 -- kind: conda - name: libcufile - version: 1.4.0.31 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcufile-1.4.0.31-0.tar.bz2 - md5: eacba45944720ae98bea25f468a11ca7 - arch: x86_64 - platform: linux - size: 561413 - timestamp: 1655921105488 -- kind: conda - name: libcufile-dev - version: 1.4.0.31 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcufile-dev-1.4.0.31-0.tar.bz2 - md5: a8dfd661b50be828ea8e58d6fdd01363 - depends: - - libcufile >=1.4.0.31 - arch: x86_64 - platform: linux - size: 1671287 - timestamp: 1655921107481 -- kind: conda - name: libcups - version: 2.3.3 - build: h4637d8d_4 - build_number: 4 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libcups-2.3.3-h4637d8d_4.conda - sha256: bc67b9b21078c99c6bd8595fe7e1ed6da1f721007726e717f0449de7032798c4 - md5: d4529f4dff3057982a7617c7ac58fde3 - depends: - - krb5 >=1.21.1,<1.22.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: Apache-2.0 - license_family: Apache - size: 4519402 - timestamp: 1689195353551 -- kind: conda - name: libcurand - version: 10.3.0.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcurand-10.3.0.86-0.tar.bz2 - md5: e0358f66f787e409b29becd898d5983f - arch: x86_64 - platform: linux - size: 55769596 - timestamp: 1661544586107 -- kind: conda - name: libcurand-dev - version: 10.3.0.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcurand-dev-10.3.0.86-0.tar.bz2 - md5: 5639b483c7c51ce2acb578444c0e10ce - depends: - - libcurand >=10.3.0.86 - arch: x86_64 - platform: linux - size: 56335986 - timestamp: 1661544618036 -- kind: conda - name: libcurl - version: 8.7.1 - build: hca28451_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.7.1-hca28451_0.conda - sha256: 82a75e9a5d9ee5b2f487d850ec5d4edc18a56eb9527608a95a916c40baae3843 - md5: 755c7f876815003337d2c61ff5d047e5 - depends: - - krb5 >=1.21.2,<1.22.0a0 - - libgcc-ng >=12 - - libnghttp2 >=1.58.0,<2.0a0 - - libssh2 >=1.11.0,<2.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - openssl >=3.2.1,<4.0a0 - - zstd >=1.5.5,<1.6.0a0 - license: curl - license_family: MIT - size: 398293 - timestamp: 1711548114077 -- kind: conda - name: libcusolver - version: 11.4.1.48 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcusolver-11.4.1.48-0.tar.bz2 - md5: a497123295be4e0bd221da5bf215f8b8 - arch: x86_64 - platform: linux - size: 101143771 - timestamp: 1661488678855 -- kind: conda - name: libcusolver-dev - version: 11.4.1.48 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcusolver-dev-11.4.1.48-0.tar.bz2 - md5: eef8b2209666925de40dc52dc2bd0036 - depends: - - libcusolver >=11.4.1.48 - arch: x86_64 - platform: linux - size: 69542891 - timestamp: 1661488763689 -- kind: conda - name: libcusparse - version: 11.7.5.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcusparse-11.7.5.86-0.tar.bz2 - md5: 853c37fabd07b5b91d3007afc82c3ed4 - arch: x86_64 - platform: linux - size: 184891885 - timestamp: 1661489463016 -- kind: conda - name: libcusparse-dev - version: 11.7.5.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libcusparse-dev-11.7.5.86-0.tar.bz2 - md5: e0c8805b9b08087d1cce37bcc270a3e4 - depends: - - libcusparse >=11.7.5.86 - arch: x86_64 - platform: linux - size: 377165256 - timestamp: 1661489561708 -- kind: conda - name: libdeflate - version: '1.20' - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.20-hd590300_0.conda - sha256: f8e0f25c382b1d0b87a9b03887a34dbd91485453f1ea991fef726dba57373612 - md5: 8e88f9389f1165d7c0936fe40d9a9a79 - depends: - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 71500 - timestamp: 1711196523408 -- kind: conda - name: libdrm - version: 2.4.120 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libdrm-2.4.120-hd590300_0.conda - sha256: 8622f52e517418ae7234081fac14a3caa8aec5d1ee5f881ca1f3b194d81c3150 - md5: 7c3071bdf1d28b331a06bda6e85ab607 - depends: - - libgcc-ng >=12 - - libpciaccess >=0.18,<0.19.0a0 - license: MIT - license_family: MIT - size: 303067 - timestamp: 1708374304366 -- kind: conda - name: libedit - version: 3.1.20191231 - build: he28a2e2_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2 - sha256: a57d37c236d8f7c886e01656f4949d9dcca131d2a0728609c6f7fa338b65f1cf - md5: 4d331e44109e3f0e19b4cb8f9b82f3e1 - depends: - - libgcc-ng >=7.5.0 - - ncurses >=6.2,<7.0.0a0 - license: BSD-2-Clause - license_family: BSD - size: 123878 - timestamp: 1597616541093 -- kind: conda - name: libev - version: '4.33' - build: hd590300_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda - sha256: 1cd6048169fa0395af74ed5d8f1716e22c19a81a8a36f934c110ca3ad4dd27b4 - md5: 172bf1cd1ff8629f2b1179945ed45055 - depends: - - libgcc-ng >=12 - license: BSD-2-Clause - license_family: BSD - size: 112766 - timestamp: 1702146165126 -- kind: conda - name: libevent - version: 2.1.12 - build: hf998b51_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda - sha256: 2e14399d81fb348e9d231a82ca4d816bf855206923759b69ad006ba482764131 - md5: a1cfcc585f0c42bf8d5546bb1dfb668d - depends: - - libgcc-ng >=12 - - openssl >=3.1.1,<4.0a0 - license: BSD-3-Clause - license_family: BSD - size: 427426 - timestamp: 1685725977222 -- kind: conda - name: libexpat - version: 2.6.2 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.6.2-h59595ed_0.conda - sha256: 331bb7c7c05025343ebd79f86ae612b9e1e74d2687b8f3179faec234f986ce19 - md5: e7ba12deb7020dd080c6c70e7b6f6a3d - depends: - - libgcc-ng >=12 - constrains: - - expat 2.6.2.* - license: MIT - license_family: MIT - size: 73730 - timestamp: 1710362120304 -- kind: conda - name: libffi - version: 3.4.2 - build: h7f98852_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2 - sha256: ab6e9856c21709b7b517e940ae7028ae0737546122f83c2aa5d692860c3b149e - md5: d645c6d2ac96843a2bfaccd2d62b3ac3 - depends: - - libgcc-ng >=9.4.0 - license: MIT - license_family: MIT - size: 58292 - timestamp: 1636488182923 -- kind: conda - name: libflac - version: 1.4.3 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libflac-1.4.3-h59595ed_0.conda - sha256: 65908b75fa7003167b8a8f0001e11e58ed5b1ef5e98b96ab2ba66d7c1b822c7d - md5: ee48bf17cc83a00f59ca1494d5646869 - depends: - - gettext >=0.21.1,<1.0a0 - - libgcc-ng >=12 - - libogg 1.3.* - - libogg >=1.3.4,<1.4.0a0 - - libstdcxx-ng >=12 - license: BSD-3-Clause - license_family: BSD - size: 394383 - timestamp: 1687765514062 -- kind: conda - name: libgcc-ng - version: 13.2.0 - build: h77fa898_7 - build_number: 7 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-13.2.0-h77fa898_7.conda - sha256: 62af2b89acbe74a21606c8410c276e57309c0a2ab8a9e8639e3c8131c0b60c92 - md5: 72ec1b1b04c4d15d4204ece1ecea5978 - depends: - - _libgcc_mutex 0.1 conda_forge - - _openmp_mutex >=4.5 - constrains: - - libgomp 13.2.0 h77fa898_7 - license: GPL-3.0-only WITH GCC-exception-3.1 - size: 775806 - timestamp: 1715016057793 -- kind: conda - name: libgcrypt - version: 1.10.3 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgcrypt-1.10.3-hd590300_0.conda - sha256: d1bd47faa29fec7288c7b212198432b07f890d3d6f646078da93b059c2e9daff - md5: 32d16ad533c59bb0a3c5ffaf16110829 - depends: - - libgcc-ng >=12 - - libgpg-error >=1.47,<2.0a0 - license: LGPL-2.1-or-later AND GPL-2.0-or-later - license_family: GPL - size: 634887 - timestamp: 1701383493365 -- kind: conda - name: libgettextpo - version: 0.22.5 - build: h59595ed_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-0.22.5-h59595ed_2.conda - sha256: e2f784564a2bdc6f753f00f63cc77c97601eb03bc89dccc4413336ec6d95490b - md5: 172bcc51059416e7ce99e7b528cede83 - depends: - - libgcc-ng >=12 - license: GPL-3.0-or-later - license_family: GPL - size: 170582 - timestamp: 1712512286907 -- kind: conda - name: libgettextpo-devel - version: 0.22.5 - build: h59595ed_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgettextpo-devel-0.22.5-h59595ed_2.conda - sha256: 695eb2439ad4a89e4205dd675cc52fba5cef6b5d41b83f07cdbf4770a336cc15 - md5: b63d9b6da3653179a278077f0de20014 - depends: - - libgcc-ng >=12 - - libgettextpo 0.22.5 h59595ed_2 - license: GPL-3.0-or-later - license_family: GPL - size: 36758 - timestamp: 1712512303244 -- kind: conda - name: libgfortran-ng - version: 13.2.0 - build: h69a702a_7 - build_number: 7 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgfortran-ng-13.2.0-h69a702a_7.conda - sha256: a588e69f96b8e0983a8cdfdbf1dc75eb48189f5420ec71150c8d8cdc0a811a9b - md5: 1b84f26d9f4f6026e179e7805d5a15cd - depends: - - libgfortran5 13.2.0 hca663fb_7 - license: GPL-3.0-only WITH GCC-exception-3.1 - size: 24314 - timestamp: 1715016272844 -- kind: conda - name: libgfortran5 - version: 13.2.0 - build: hca663fb_7 - build_number: 7 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-13.2.0-hca663fb_7.conda - sha256: 754ab038115edce550fdccdc9ddf7dead2fa8346b8cdd4428c59ae1e83293978 - md5: c0bd771f09a326fdcd95a60b617795bf - depends: - - libgcc-ng >=13.2.0 - constrains: - - libgfortran-ng 13.2.0 - license: GPL-3.0-only WITH GCC-exception-3.1 - size: 1441361 - timestamp: 1715016068766 -- kind: conda - name: libglib - version: 2.80.0 - build: hf2295e7_6 - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libglib-2.80.0-hf2295e7_6.conda - sha256: d2867a1515676f3b64265420598badb2e4ad2369d85237fb276173a99959eb37 - md5: 9342e7c44c38bea649490f72d92c382d - depends: - - libffi >=3.4,<4.0a0 - - libgcc-ng >=12 - - libiconv >=1.17,<2.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - pcre2 >=10.43,<10.44.0a0 - constrains: - - glib 2.80.0 *_6 - license: LGPL-2.1-or-later - size: 3942450 - timestamp: 1713639388280 -- kind: conda - name: libglu - version: 9.0.0 - build: hac7e632_1003 - build_number: 1003 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libglu-9.0.0-hac7e632_1003.conda - sha256: 8368435c41105dc3e1c02896a02ecaa21b77d0b0d67fc8b06a16ba885c86f917 - md5: 50c389a09b6b7babaef531eb7cb5e0ca - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libxcb >=1.15,<1.16.0a0 - - xorg-libx11 >=1.8.6,<2.0a0 - - xorg-libxext >=1.3.4,<2.0a0 - - xorg-xextproto >=7.3.0,<8.0a0 - license: SGI-2 - size: 331249 - timestamp: 1694431884320 -- kind: conda - name: libgoogle-cloud - version: 2.23.0 - build: h9be4e54_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.23.0-h9be4e54_1.conda - sha256: 680f5a9bc45aa905d9da086b16551438553649e05dd6b94b02b379b050602d5e - md5: 1042d8401bb268553f98e60120cdeb40 - depends: - - libabseil * cxx17* - - libabseil >=20240116.1,<20240117.0a0 - - libcurl >=8.7.1,<9.0a0 - - libgcc-ng >=12 - - libgrpc >=1.62.2,<1.63.0a0 - - libprotobuf >=4.25.3,<4.25.4.0a0 - - libstdcxx-ng >=12 - - openssl >=3.2.1,<4.0a0 - constrains: - - libgoogle-cloud 2.23.0 *_1 - license: Apache-2.0 - license_family: Apache - size: 1214608 - timestamp: 1713798219648 -- kind: conda - name: libgoogle-cloud-storage - version: 2.23.0 - build: hc7a4891_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.23.0-hc7a4891_1.conda - sha256: b85ce8b78e9262670a145a1639e253708e2a9eb9100d60ccec16f8e41d87a4bb - md5: ee99fb9107ffb579b58ee92a5fb14b06 - depends: - - libabseil - - libcrc32c >=1.1.2,<1.2.0a0 - - libcurl - - libgcc-ng >=12 - - libgoogle-cloud 2.23.0 h9be4e54_1 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - openssl - license: Apache-2.0 - license_family: Apache - size: 752661 - timestamp: 1713798390317 -- kind: conda - name: libgpg-error - version: '1.49' - build: h4f305b6_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgpg-error-1.49-h4f305b6_0.conda - sha256: b2664c2c11211a63856f23278efb49d3e65d902297989a0c12dcd228b5d97110 - md5: dfcfd72c7a430d3616763ecfbefe4ca9 - depends: - - gettext - - libasprintf >=0.22.5,<1.0a0 - - libgcc-ng >=12 - - libgettextpo >=0.22.5,<1.0a0 - - libstdcxx-ng >=12 - license: GPL-2.0-only - license_family: GPL - size: 263319 - timestamp: 1714121531915 -- kind: conda - name: libgrpc - version: 1.62.2 - build: h15f2491_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.62.2-h15f2491_0.conda - sha256: 28241ed89335871db33cb6010e9ccb2d9e9b6bb444ddf6884f02f0857363c06a - md5: 8dabe607748cb3d7002ad73cd06f1325 - depends: - - c-ares >=1.28.1,<2.0a0 - - libabseil * cxx17* - - libabseil >=20240116.1,<20240117.0a0 - - libgcc-ng >=12 - - libprotobuf >=4.25.3,<4.25.4.0a0 - - libre2-11 >=2023.9.1,<2024.0a0 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - openssl >=3.2.1,<4.0a0 - - re2 - constrains: - - grpc-cpp =1.62.2 - license: Apache-2.0 - license_family: APACHE - size: 7316832 - timestamp: 1713390645548 -- kind: conda - name: libhwloc - version: 2.10.0 - build: default_h2fb2949_1000 - build_number: 1000 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libhwloc-2.10.0-default_h2fb2949_1000.conda - sha256: dab61dff22f40367e57b1fe024e789f451b7511e65c32b97ada97ca549dd8dbc - md5: 7e3726e647a619c6ce5939014dfde86d - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libxml2 >=2.12.6,<3.0a0 - license: BSD-3-Clause - license_family: BSD - size: 2412713 - timestamp: 1711490522117 -- kind: conda - name: libiconv - version: '1.17' - build: hd590300_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.17-hd590300_2.conda - sha256: 8ac2f6a9f186e76539439e50505d98581472fedb347a20e7d1f36429849f05c9 - md5: d66573916ffcf376178462f1b61c941e - depends: - - libgcc-ng >=12 - license: LGPL-2.1-only - size: 705775 - timestamp: 1702682170569 -- kind: conda - name: libidn2 - version: 2.3.7 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libidn2-2.3.7-hd590300_0.conda - sha256: 253f9be445c58bf07b39d8f67ac08bccc5010c75a8c2070cddfb6c20e1ca4f4f - md5: 2b7b0d827c6447cc1d85dc06d5b5de46 - depends: - - gettext >=0.21.1,<1.0a0 - - libgcc-ng >=12 - - libunistring >=0,<1.0a0 - license: LGPLv2 - size: 126515 - timestamp: 1706368269716 -- kind: conda - name: libjpeg-turbo - version: 3.0.0 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.0.0-hd590300_1.conda - sha256: b954e09b7e49c2f2433d6f3bb73868eda5e378278b0f8c1dd10a7ef090e14f2f - md5: ea25936bb4080d843790b586850f82b8 - depends: - - libgcc-ng >=12 - constrains: - - jpeg <0.0.0a - license: IJG AND BSD-3-Clause AND Zlib - size: 618575 - timestamp: 1694474974816 -- kind: conda - name: liblapack - version: 3.9.0 - build: 5_h92ddd45_netlib - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-5_h92ddd45_netlib.tar.bz2 - sha256: 41eb83ea6ce409fd8c81fc38e029422840f581022e6f33998a680c0b23884cd6 - md5: ffb80081cf8f43903b07045630188851 - depends: - - libblas 3.9.0.* - - libgcc-ng >=9.3.0 - - libgfortran-ng - - libgfortran5 >=9.3.0 - track_features: - - blas_netlib - license: BSD-3-Clause - license_family: BSD - size: 3111106 - timestamp: 1618011727809 -- kind: conda - name: libllvm15 - version: 15.0.7 - build: hb3ce162_4 - build_number: 4 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libllvm15-15.0.7-hb3ce162_4.conda - sha256: e71584c0f910140630580fdd0a013029a52fd31e435192aea2aa8d29005262d1 - md5: 8a35df3cbc0c8b12cc8af9473ae75eef - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libxml2 >=2.12.1,<3.0.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - zstd >=1.5.5,<1.6.0a0 - license: Apache-2.0 WITH LLVM-exception - license_family: Apache - size: 33321457 - timestamp: 1701375836233 -- kind: conda - name: libllvm16 - version: 16.0.6 - build: hb3ce162_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libllvm16-16.0.6-hb3ce162_3.conda - sha256: 624fa4012397bc5a8c9269247bf9baa7d907eb59079aefc6f6fa6a40f10fd0ba - md5: a4d48c40dd5c60edbab7fd69c9a88967 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libxml2 >=2.12.1,<3.0.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - zstd >=1.5.5,<1.6.0a0 - license: Apache-2.0 WITH LLVM-exception - license_family: Apache - size: 35359734 - timestamp: 1701375139881 -- kind: conda - name: libllvm18 - version: 18.1.5 - build: hb77312f_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libllvm18-18.1.5-hb77312f_0.conda - sha256: 2e0a7c023b2df11bd316baad7c409bc95f2e7a92a322ab7973c08d72d03653d2 - md5: efd221d3668077ca067a206269418dec - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libxml2 >=2.12.6,<3.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - zstd >=1.5.6,<1.6.0a0 - license: Apache-2.0 WITH LLVM-exception - license_family: Apache - size: 38403202 - timestamp: 1714775293919 -- kind: conda - name: libnghttp2 - version: 1.58.0 - build: h47da74e_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.58.0-h47da74e_1.conda - sha256: 1910c5306c6aa5bcbd623c3c930c440e9c77a5a019008e1487810e3c1d3716cb - md5: 700ac6ea6d53d5510591c4344d5c989a - depends: - - c-ares >=1.23.0,<2.0a0 - - libev >=4.33,<4.34.0a0 - - libev >=4.33,<5.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - openssl >=3.2.0,<4.0a0 - license: MIT - license_family: MIT - size: 631936 - timestamp: 1702130036271 -- kind: conda - name: libnl - version: 3.9.0 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libnl-3.9.0-hd590300_0.conda - sha256: aae03117811e704c3f3666e8374dd2e632f1d78bef0c27330e7298b24004819e - md5: d27c451db4f1d3c983c78167d2fdabc2 - depends: - - libgcc-ng >=12 - license: LGPL-2.1-or-later - license_family: LGPL - size: 732866 - timestamp: 1702657849946 -- kind: conda - name: libnpp - version: 11.8.0.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libnpp-11.8.0.86-0.tar.bz2 - md5: 03822c4b5dae5988ba9dcb7eae837345 - arch: x86_64 - platform: linux - size: 154995740 - timestamp: 1661489365078 -- kind: conda - name: libnpp-dev - version: 11.8.0.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libnpp-dev-11.8.0.86-0.tar.bz2 - md5: dde377399a27bb87e124db9c8b898e32 - depends: - - libnpp >=11.8.0.86 - arch: x86_64 - platform: linux - size: 151472361 - timestamp: 1661489433906 -- kind: conda - name: libnsl - version: 2.0.1 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hd590300_0.conda - sha256: 26d77a3bb4dceeedc2a41bd688564fe71bf2d149fdcf117049970bc02ff1add6 - md5: 30fd6e37fe21f86f4bd26d6ee73eeec7 - depends: - - libgcc-ng >=12 - license: LGPL-2.1-only - license_family: GPL - size: 33408 - timestamp: 1697359010159 -- kind: conda - name: libnvjpeg - version: 11.9.0.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libnvjpeg-11.9.0.86-0.tar.bz2 - md5: e42d6f0f20feb0cba0165d5cae33362f - arch: x86_64 - platform: linux - size: 2508741 - timestamp: 1661545915358 -- kind: conda - name: libnvjpeg-dev - version: 11.9.0.86 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/libnvjpeg-dev-11.9.0.86-0.tar.bz2 - md5: 3fa3184a0180608546e54934be2e4a26 - depends: - - libnvjpeg >=11.9.0.86 - arch: x86_64 - platform: linux - size: 2166145 - timestamp: 1661545917152 -- kind: conda - name: libogg - version: 1.3.4 - build: h7f98852_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libogg-1.3.4-h7f98852_1.tar.bz2 - sha256: b88afeb30620b11bed54dac4295aa57252321446ba4e6babd7dce4b9ffde9b25 - md5: 6e8cc2173440d77708196c5b93771680 - depends: - - libgcc-ng >=9.3.0 - license: BSD-3-Clause - license_family: BSD - size: 210550 - timestamp: 1610382007814 -- kind: conda - name: libopenvino - version: 2024.0.0 - build: h2da1b83_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-2024.0.0-h2da1b83_5.conda - sha256: ef0f39b7378663c296cddc184f0a028d6a5178fc61d145fd9407f635edb15de7 - md5: 87d1f91d897ed6678a615536a25fd13f - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - pugixml >=1.14,<1.15.0a0 - - tbb >=2021.11.0 - size: 5113894 - timestamp: 1712674184348 -- kind: conda - name: libopenvino-auto-batch-plugin - version: 2024.0.0 - build: hb045406_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-batch-plugin-2024.0.0-hb045406_5.conda - sha256: 51aff831cbb65ee29ddd977c66a5a0224b2580ea7fe131885054bc8effa74e4f - md5: ddbb87c004506e586b79b674f0696aa3 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libstdcxx-ng >=12 - - tbb >=2021.11.0 - size: 110915 - timestamp: 1712674229190 -- kind: conda - name: libopenvino-auto-plugin - version: 2024.0.0 - build: hb045406_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-auto-plugin-2024.0.0-hb045406_5.conda - sha256: 63c26a03ea8953cccde1302b26520ef53dccce6d1e234c25fc249c1ea75f14d1 - md5: 59aad82eda612aa46ba300576d536966 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libstdcxx-ng >=12 - - tbb >=2021.11.0 - size: 228961 - timestamp: 1712674245147 -- kind: conda - name: libopenvino-hetero-plugin - version: 2024.0.0 - build: h5c03a75_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-hetero-plugin-2024.0.0-h5c03a75_5.conda - sha256: 41ab26306eeadc35b1765ae49ea651429e39239e51140cbe695ecd7e5111d9c9 - md5: c69a1ed3e89dc16c7e1df30ed1fd73f7 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libstdcxx-ng >=12 - - pugixml >=1.14,<1.15.0a0 - size: 179737 - timestamp: 1712674261368 -- kind: conda - name: libopenvino-intel-cpu-plugin - version: 2024.0.0 - build: h2da1b83_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-cpu-plugin-2024.0.0-h2da1b83_5.conda - sha256: 41a31574f67e01e012ff7691c2bf2bcf24298307991f9e8b04b756bf0cd42be3 - md5: deb11c7339478aba1b5b7cf15c443396 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libstdcxx-ng >=12 - - pugixml >=1.14,<1.15.0a0 - - tbb >=2021.11.0 - size: 10628363 - timestamp: 1712674280576 -- kind: conda - name: libopenvino-intel-gpu-plugin - version: 2024.0.0 - build: h2da1b83_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-intel-gpu-plugin-2024.0.0-h2da1b83_5.conda - sha256: 0d691749d38bf7a1b5f347336486c126af9591e427486aae92f465f6c0ea7d66 - md5: 1f5902112c12e9a8ae2bb4c51294d35a - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libstdcxx-ng >=12 - - ocl-icd >=2.3.2,<3.0a0 - - pugixml >=1.14,<1.15.0a0 - - tbb >=2021.11.0 - size: 8353537 - timestamp: 1712674327020 -- kind: conda - name: libopenvino-ir-frontend - version: 2024.0.0 - build: h5c03a75_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-ir-frontend-2024.0.0-h5c03a75_5.conda - sha256: c1e8556f42cd001ee03298c6b044730daae2adcc1af035df0edccf8eb4dd5261 - md5: 3a5e6778c907c33503be9c051a6424ae - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libstdcxx-ng >=12 - - pugixml >=1.14,<1.15.0a0 - size: 200926 - timestamp: 1712674364843 -- kind: conda - name: libopenvino-onnx-frontend - version: 2024.0.0 - build: h07e8aee_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-onnx-frontend-2024.0.0-h07e8aee_5.conda - sha256: 68506cc32799197fecdceb50a220c8ad5092c0279192bd2c0ecc33f57beb2397 - md5: 5b9b0c983e7b14ba4764d75a9bf7a6f3 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libprotobuf >=4.25.3,<4.25.4.0a0 - - libstdcxx-ng >=12 - size: 1586243 - timestamp: 1712674383761 -- kind: conda - name: libopenvino-paddle-frontend - version: 2024.0.0 - build: h07e8aee_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-paddle-frontend-2024.0.0-h07e8aee_5.conda - sha256: 7ad02d506f4a67b37f1c3ec72c950d339c10c29a53a36326094fbbfa62ec3cd1 - md5: 77ba4135acc68fdade36cca31446c3e8 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libprotobuf >=4.25.3,<4.25.4.0a0 - - libstdcxx-ng >=12 - size: 695337 - timestamp: 1712674402836 -- kind: conda - name: libopenvino-pytorch-frontend - version: 2024.0.0 - build: he02047a_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-pytorch-frontend-2024.0.0-he02047a_5.conda - sha256: 71795c64c5b6a853130fefb435376b836a6e42eac63117a03a78fa82d76f4af0 - md5: deb1f6397c3aa6dbb35d197499829623 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libstdcxx-ng >=12 - size: 1066396 - timestamp: 1712674419569 -- kind: conda - name: libopenvino-tensorflow-frontend - version: 2024.0.0 - build: h39126c6_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-frontend-2024.0.0-h39126c6_5.conda - sha256: d3302692d306eb59f99650393a5f3a7f9312bde5c2a3982432fb667ee4f1d89c - md5: 737f0ee3a70c84758333318afa86d46e - depends: - - __glibc >=2.17,<3.0.a0 - - libabseil * cxx17* - - libabseil >=20240116.1,<20240117.0a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libprotobuf >=4.25.3,<4.25.4.0a0 - - libstdcxx-ng >=12 - - snappy >=1.2.0,<1.3.0a0 - size: 1270703 - timestamp: 1712674438216 -- kind: conda - name: libopenvino-tensorflow-lite-frontend - version: 2024.0.0 - build: he02047a_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopenvino-tensorflow-lite-frontend-2024.0.0-he02047a_5.conda - sha256: 33d537f0a7d43e384e9808191f79ae2115213ff78d291bab3d57db9d9c66683a - md5: 5161e70dfbcd31a6e28b5d75c0b620e6 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libopenvino 2024.0.0 h2da1b83_5 - - libstdcxx-ng >=12 - size: 477616 - timestamp: 1712674457796 -- kind: conda - name: libopus - version: 1.3.1 - build: h7f98852_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libopus-1.3.1-h7f98852_1.tar.bz2 - sha256: 0e1c2740ebd1c93226dc5387461bbcf8142c518f2092f3ea7551f77755decc8f - md5: 15345e56d527b330e1cacbdf58676e8f - depends: - - libgcc-ng >=9.3.0 - license: BSD-3-Clause - license_family: BSD - size: 260658 - timestamp: 1606823578035 -- kind: conda - name: libparquet - version: 15.0.2 - build: hacf5a1f_6_cpu - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libparquet-15.0.2-hacf5a1f_6_cpu.conda - sha256: ac842454e033b8ad638eec0e0672db8e82d7a53d6c5f61ec93badcee02373966 - md5: 37d4b8f700247904e94d8fb0a90e488e - depends: - - gflags >=2.2.2,<2.3.0a0 - - libarrow 15.0.2 hefa796f_6_cpu - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libthrift >=0.19.0,<0.19.1.0a0 - - openssl >=3.2.1,<4.0a0 - license: Apache-2.0 - license_family: APACHE - size: 1181574 - timestamp: 1714448276294 -- kind: conda - name: libpciaccess - version: '0.18' - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libpciaccess-0.18-hd590300_0.conda - sha256: c0a30ac74eba66ea76a4f0a39acc7833f5ed783a632ca3bb6665b2d81aabd2fb - md5: 48f4330bfcd959c3cfb704d424903c82 - depends: - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 28361 - timestamp: 1707101388552 -- kind: conda - name: libpng - version: 1.6.43 - build: h2797004_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.43-h2797004_0.conda - sha256: 502f6ff148ac2777cc55ae4ade01a8fc3543b4ffab25c4e0eaa15f94e90dd997 - md5: 009981dd9cfcaa4dbfa25ffaed86bcae - depends: - - libgcc-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: zlib-acknowledgement - size: 288221 - timestamp: 1708780443939 -- kind: conda - name: libpq - version: '16.2' - build: h33b98f1_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libpq-16.2-h33b98f1_1.conda - sha256: e03a8439b79e013840c44c957d37dbce10316888b2b5dc7dcfcfc0cfe3a3b128 - md5: 9e49ec2a61d02623b379dc332eb6889d - depends: - - krb5 >=1.21.2,<1.22.0a0 - - libgcc-ng >=12 - - openssl >=3.2.1,<4.0a0 - license: PostgreSQL - size: 2601973 - timestamp: 1710863646063 -- kind: conda - name: libprotobuf - version: 4.25.3 - build: h08a7969_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-4.25.3-h08a7969_0.conda - sha256: 70e0eef046033af2e8d21251a785563ad738ed5281c74e21c31c457780845dcd - md5: 6945825cebd2aeb16af4c69d97c32c13 - depends: - - libabseil * cxx17* - - libabseil >=20240116.1,<20240117.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: BSD-3-Clause - license_family: BSD - size: 2811207 - timestamp: 1709514552541 -- kind: conda - name: libraw - version: 0.21.1 - build: h2a13503_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libraw-0.21.1-h2a13503_2.conda - sha256: a23ab9470bbf0ae0505b2991f139085e0a99b32f8640a22d3c540b515c352301 - md5: 63ab3e0cf149917a08af38b2786320c0 - depends: - - _openmp_mutex >=4.5 - - lcms2 >=2.15,<3.0a0 - - libgcc-ng >=12 - - libjpeg-turbo >=3.0.0,<4.0a0 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: LGPL-2.1-only - license_family: LGPL - size: 637871 - timestamp: 1695983515562 -- kind: conda - name: libre2-11 - version: 2023.09.01 - build: h5a48ba9_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2023.09.01-h5a48ba9_2.conda - sha256: 3f3c65fe0e9e328b4c1ebc2b622727cef3e5b81b18228cfa6cf0955bc1ed8eff - md5: 41c69fba59d495e8cf5ffda48a607e35 - depends: - - libabseil * cxx17* - - libabseil >=20240116.1,<20240117.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - constrains: - - re2 2023.09.01.* - license: BSD-3-Clause - license_family: BSD - size: 232603 - timestamp: 1708946763521 -- kind: conda - name: libsndfile - version: 1.2.2 - build: hc60ed4a_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libsndfile-1.2.2-hc60ed4a_1.conda - sha256: f709cbede3d4f3aee4e2f8d60bd9e256057f410bd60b8964cb8cf82ec1457573 - md5: ef1910918dd895516a769ed36b5b3a4e - depends: - - lame >=3.100,<3.101.0a0 - - libflac >=1.4.3,<1.5.0a0 - - libgcc-ng >=12 - - libogg >=1.3.4,<1.4.0a0 - - libopus >=1.3.1,<2.0a0 - - libstdcxx-ng >=12 - - libvorbis >=1.3.7,<1.4.0a0 - - mpg123 >=1.32.1,<1.33.0a0 - license: LGPL-2.1-or-later - license_family: LGPL - size: 354372 - timestamp: 1695747735668 -- kind: conda - name: libsqlite - version: 3.45.3 - build: h2797004_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.45.3-h2797004_0.conda - sha256: e2273d6860eadcf714a759ffb6dc24a69cfd01f2a0ea9d6c20f86049b9334e0c - md5: b3316cbe90249da4f8e84cd66e1cc55b - depends: - - libgcc-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: Unlicense - size: 859858 - timestamp: 1713367435849 -- kind: conda - name: libssh2 - version: 1.11.0 - build: h0841786_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.0-h0841786_0.conda - sha256: 50e47fd9c4f7bf841a11647ae7486f65220cfc988ec422a4475fe8d5a823824d - md5: 1f5a58e686b13bcfde88b93f547d23fe - depends: - - libgcc-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - openssl >=3.1.1,<4.0a0 - license: BSD-3-Clause - license_family: BSD - size: 271133 - timestamp: 1685837707056 -- kind: conda - name: libstdcxx-ng - version: 13.2.0 - build: hc0a3c3a_7 - build_number: 7 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-13.2.0-hc0a3c3a_7.conda - sha256: 35f1e08be0a84810c9075f5bd008495ac94e6c5fe306dfe4b34546f11fed850f - md5: 53ebd4c833fa01cb2c6353e99f905406 - license: GPL-3.0-only WITH GCC-exception-3.1 - size: 3837704 - timestamp: 1715016117360 -- kind: conda - name: libsystemd0 - version: '255' - build: h3516f8a_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libsystemd0-255-h3516f8a_1.conda - sha256: af27b0d225435d03f378a119f8eab6b280c53557a3c84cdb3bb8fd3167615aed - md5: 3366af27f0b593544a6cd453c7932ac5 - depends: - - __glibc >=2.17,<3.0.a0 - - libcap >=2.69,<2.70.0a0 - - libgcc-ng >=12 - - libgcrypt >=1.10.3,<2.0a0 - - lz4-c >=1.9.3,<1.10.0a0 - - xz >=5.2.6,<6.0a0 - - zstd >=1.5.5,<1.6.0a0 - license: LGPL-2.1-or-later - size: 402592 - timestamp: 1709568499820 -- kind: conda - name: libtasn1 - version: 4.19.0 - build: h166bdaf_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libtasn1-4.19.0-h166bdaf_0.tar.bz2 - sha256: 5bfeada0e1c6ec2574afe2d17cdbc39994d693a41431338a6cb9dfa7c4d7bfc8 - md5: 93840744a8552e9ebf6bb1a5dffc125a - depends: - - libgcc-ng >=12 - license: GPL-3.0-or-later - license_family: GPL - size: 116878 - timestamp: 1661325701583 -- kind: conda - name: libthrift - version: 0.19.0 - build: hb90f79a_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libthrift-0.19.0-hb90f79a_1.conda - sha256: 719add2cf20d144ef9962c57cd0f77178259bdb3aae1cded2e2b2b7c646092f5 - md5: 8cdb7d41faa0260875ba92414c487e2d - depends: - - libevent >=2.1.12,<2.1.13.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - openssl >=3.1.3,<4.0a0 - license: Apache-2.0 - license_family: APACHE - size: 409409 - timestamp: 1695958011498 -- kind: conda - name: libtiff - version: 4.6.0 - build: h1dd3fc0_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.6.0-h1dd3fc0_3.conda - sha256: fc3b210f9584a92793c07396cb93e72265ff3f1fa7ca629128bf0a50d5cb15e4 - md5: 66f03896ffbe1a110ffda05c7a856504 - depends: - - lerc >=4.0.0,<5.0a0 - - libdeflate >=1.20,<1.21.0a0 - - libgcc-ng >=12 - - libjpeg-turbo >=3.0.0,<4.0a0 - - libstdcxx-ng >=12 - - libwebp-base >=1.3.2,<2.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - xz >=5.2.6,<6.0a0 - - zstd >=1.5.5,<1.6.0a0 - license: HPND - size: 282688 - timestamp: 1711217970425 -- kind: conda - name: libunistring - version: 0.9.10 - build: h7f98852_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libunistring-0.9.10-h7f98852_0.tar.bz2 - sha256: e88c45505921db29c08df3439ddb7f771bbff35f95e7d3103bf365d5d6ce2a6d - md5: 7245a044b4a1980ed83196176b78b73a - depends: - - libgcc-ng >=9.3.0 - license: GPL-3.0-only OR LGPL-3.0-only - size: 1433436 - timestamp: 1626955018689 -- kind: conda - name: libutf8proc - version: 2.8.0 - build: h166bdaf_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libutf8proc-2.8.0-h166bdaf_0.tar.bz2 - sha256: 49082ee8d01339b225f7f8c60f32a2a2c05fe3b16f31b554b4fb2c1dea237d1c - md5: ede4266dc02e875fe1ea77b25dd43747 - depends: - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 101070 - timestamp: 1667316029302 -- kind: conda - name: libuuid - version: 2.38.1 - build: h0b41bf4_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.38.1-h0b41bf4_0.conda - sha256: 787eb542f055a2b3de553614b25f09eefb0a0931b0c87dbcce6efdfd92f04f18 - md5: 40b61aab5c7ba9ff276c41cfffe6b80b - depends: - - libgcc-ng >=12 - license: BSD-3-Clause - license_family: BSD - size: 33601 - timestamp: 1680112270483 -- kind: conda - name: libva - version: 2.21.0 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libva-2.21.0-hd590300_0.conda - sha256: b4e3a3fa523a5ddd1eca7981c9d6a9b831a182950116cc5bda18c94a040b63bc - md5: e50a2609159a3e336fe4092738c00687 - depends: - - libdrm >=2.4.120,<2.5.0a0 - - xorg-libx11 >=1.8.7,<2.0a0 - - xorg-libxext >=1.3.4,<2.0a0 - - xorg-libxfixes - license: MIT - license_family: MIT - size: 189313 - timestamp: 1710242676665 -- kind: conda - name: libvorbis - version: 1.3.7 - build: h9c3ff4c_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libvorbis-1.3.7-h9c3ff4c_0.tar.bz2 - sha256: 53080d72388a57b3c31ad5805c93a7328e46ff22fab7c44ad2a86d712740af33 - md5: 309dec04b70a3cc0f1e84a4013683bc0 - depends: - - libgcc-ng >=9.3.0 - - libogg >=1.3.4,<1.4.0a0 - - libstdcxx-ng >=9.3.0 - license: BSD-3-Clause - license_family: BSD - size: 286280 - timestamp: 1610609811627 -- kind: conda - name: libvpx - version: 1.14.0 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libvpx-1.14.0-h59595ed_0.conda - sha256: b0e0500fc92f626baaa2cf926dece5ce7571c42a2db2d993a250d4c5da4d68ca - md5: 01c76c6d71097a0f3bd8683a8f255123 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: BSD-3-Clause - license_family: BSD - size: 1019593 - timestamp: 1707175376125 -- kind: conda - name: libwebp-base - version: 1.4.0 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.4.0-hd590300_0.conda - sha256: 49bc5f6b1e11cb2babf2a2a731d1a680a5e08a858280876a779dbda06c78c35f - md5: b26e8aa824079e1be0294e7152ca4559 - depends: - - libgcc-ng >=12 - constrains: - - libwebp 1.4.0 - license: BSD-3-Clause - license_family: BSD - size: 438953 - timestamp: 1713199854503 -- kind: conda - name: libxcb - version: '1.15' - build: h0b41bf4_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.15-h0b41bf4_0.conda - sha256: a670902f0a3173a466c058d2ac22ca1dd0df0453d3a80e0212815c20a16b0485 - md5: 33277193f5b92bad9fdd230eb700929c - depends: - - libgcc-ng >=12 - - pthread-stubs - - xorg-libxau - - xorg-libxdmcp - license: MIT - license_family: MIT - size: 384238 - timestamp: 1682082368177 -- kind: conda - name: libxcrypt - version: 4.4.36 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda - sha256: 6ae68e0b86423ef188196fff6207ed0c8195dd84273cb5623b85aa08033a410c - md5: 5aa797f8787fe7a17d1b0821485b5adc - depends: - - libgcc-ng >=12 - license: LGPL-2.1-or-later - size: 100393 - timestamp: 1702724383534 -- kind: conda - name: libxkbcommon - version: 1.7.0 - build: h662e7e4_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libxkbcommon-1.7.0-h662e7e4_0.conda - sha256: 3d97d7f964237f42452295d461afdbc51e93f72e2c80be516f56de80e3bb6621 - md5: b32c0da42b1f24a98577bb3d7fc0b995 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libxcb >=1.15,<1.16.0a0 - - libxml2 >=2.12.6,<3.0a0 - - xkeyboard-config - - xorg-libxau >=1.0.11,<2.0a0 - license: MIT/X11 Derivative - license_family: MIT - size: 593534 - timestamp: 1711303445595 -- kind: conda - name: libxml2 - version: 2.12.6 - build: h232c23b_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.12.6-h232c23b_2.conda - sha256: 0fd41df7211aae04f492c8550ce10238e8cfa8b1abebc2215a983c5e66d284ea - md5: 9a3a42df8a95f65334dfc7b80da1195d - depends: - - icu >=73.2,<74.0a0 - - libgcc-ng >=12 - - libiconv >=1.17,<2.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - xz >=5.2.6,<6.0a0 - license: MIT - license_family: MIT - size: 704938 - timestamp: 1713314718258 -- kind: conda - name: libzlib - version: 1.2.13 - build: hd590300_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.2.13-hd590300_5.conda - sha256: 370c7c5893b737596fd6ca0d9190c9715d89d888b8c88537ae1ef168c25e82e4 - md5: f36c115f1ee199da648e0597ec2047ad - depends: - - libgcc-ng >=12 - constrains: - - zlib 1.2.13 *_5 - license: Zlib - license_family: Other - size: 61588 - timestamp: 1686575217516 -- kind: pypi - name: lightning-utilities - version: 0.11.2 - url: https://files.pythonhosted.org/packages/5e/9e/e7768a8e363fc6f0c978bb7a0aa7641f10d80be60000e788ef2f01d34a7c/lightning_utilities-0.11.2-py3-none-any.whl - sha256: 541f471ed94e18a28d72879338c8c52e873bb46f4c47644d89228faeb6751159 - requires_dist: - - packaging >=17.1 - - setuptools - - typing-extensions - - importlib-metadata >=4.0.0 ; python_version < '3.8' - - fire ; extra == 'cli' - - requests >=2.0.0 ; extra == 'docs' - - mypy >=1.0.0 ; extra == 'typing' - - types-setuptools ; extra == 'typing' - requires_python: '>=3.8' -- kind: conda - name: llvm-openmp - version: 15.0.7 - build: h0cdce71_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/llvm-openmp-15.0.7-h0cdce71_0.conda - sha256: 7c67d383a8b1f3e7bf9e046e785325c481f6868194edcfb9d78d261da4ad65d4 - md5: 589c9a3575a050b583241c3d688ad9aa - depends: - - libzlib >=1.2.13,<1.3.0a0 - constrains: - - openmp 15.0.7|15.0.7.* - license: Apache-2.0 WITH LLVM-exception - license_family: APACHE - size: 3268766 - timestamp: 1673584331056 -- kind: pypi - name: lxml - version: 5.2.1 - url: https://files.pythonhosted.org/packages/61/8a/a0a71720da1c61fd6a55a1962ec1280cebc4552c319efe744c8aa99d28c5/lxml-5.2.1-cp310-cp310-manylinux_2_28_x86_64.whl - sha256: a2b44bec7adf3e9305ce6cbfa47a4395667e744097faed97abb4728748ba7d47 - requires_dist: - - cssselect >=0.7 ; extra == 'cssselect' - - html5lib ; extra == 'html5' - - lxml-html-clean ; extra == 'html_clean' - - beautifulsoup4 ; extra == 'htmlsoup' - - cython >=3.0.10 ; extra == 'source' - requires_python: '>=3.6' -- kind: conda - name: lz4-c - version: 1.9.4 - build: hcb278e6_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.4-hcb278e6_0.conda - sha256: 1b4c105a887f9b2041219d57036f72c4739ab9e9fe5a1486f094e58c76b31f5f - md5: 318b08df404f9c9be5712aaa5a6f0bb0 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: BSD-2-Clause - license_family: BSD - size: 143402 - timestamp: 1674727076728 -- kind: pypi - name: mapbox-earcut - version: 1.0.1 - url: https://files.pythonhosted.org/packages/a9/6d/8b08b54435ee0b2b1d0d3b9a5e212cc42f4dce08cd6e2441b3b9d216471a/mapbox_earcut-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 20929541c1c9f5fefde45c6c33e8ed3138c7bdd1034ced998877913878f3457c - requires_dist: - - numpy - - pytest ; extra == 'test' -- kind: pypi - name: markdown - version: '3.6' - url: https://files.pythonhosted.org/packages/fc/b3/0c0c994fe49cd661084f8d5dc06562af53818cc0abefaca35bdc894577c3/Markdown-3.6-py3-none-any.whl - sha256: 48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f - requires_dist: - - importlib-metadata >=4.4 ; python_version < '3.10' - - mkdocs >=1.5 ; extra == 'docs' - - mkdocs-nature >=0.6 ; extra == 'docs' - - mdx-gh-links >=0.2 ; extra == 'docs' - - mkdocstrings[python] ; extra == 'docs' - - mkdocs-gen-files ; extra == 'docs' - - mkdocs-section-index ; extra == 'docs' - - mkdocs-literate-nav ; extra == 'docs' - - coverage ; extra == 'testing' - - pyyaml ; extra == 'testing' - requires_python: '>=3.8' -- kind: pypi - name: markdown-it-py - version: 3.0.0 - url: https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl - sha256: 355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 - requires_dist: - - mdurl ~=0.1 - - psutil ; extra == 'benchmarking' - - pytest ; extra == 'benchmarking' - - pytest-benchmark ; extra == 'benchmarking' - - pre-commit ~=3.0 ; extra == 'code_style' - - commonmark ~=0.9 ; extra == 'compare' - - markdown ~=3.4 ; extra == 'compare' - - mistletoe ~=1.0 ; extra == 'compare' - - mistune ~=2.0 ; extra == 'compare' - - panflute ~=2.3 ; extra == 'compare' - - linkify-it-py >=1, <3 ; extra == 'linkify' - - mdit-py-plugins ; extra == 'plugins' - - gprof2dot ; extra == 'profiling' - - mdit-py-plugins ; extra == 'rtd' - - myst-parser ; extra == 'rtd' - - pyyaml ; extra == 'rtd' - - sphinx ; extra == 'rtd' - - sphinx-copybutton ; extra == 'rtd' - - sphinx-design ; extra == 'rtd' - - sphinx-book-theme ; extra == 'rtd' - - jupyter-sphinx ; extra == 'rtd' - - coverage ; extra == 'testing' - - pytest ; extra == 'testing' - - pytest-cov ; extra == 'testing' - - pytest-regressions ; extra == 'testing' - requires_python: '>=3.8' -- kind: conda - name: markupsafe - version: 2.1.5 - build: py310h2372a71_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.5-py310h2372a71_0.conda - sha256: 3c18347adf1d091ee9248612308a6bef79038f80b626ef67f58cd0e8d25c65b8 - md5: f6703fa0214a00bf49d1bef6dc7672d0 - depends: - - libgcc-ng >=12 - - python >=3.10,<3.11.0a0 - - python_abi 3.10.* *_cp310 - constrains: - - jinja2 >=3.0.0 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/markupsafe - size: 24493 - timestamp: 1706900070478 -- kind: pypi - name: matplotlib - version: 3.8.4 - url: https://files.pythonhosted.org/packages/d6/07/061f97211f942101070a46fecd813a6b1bd83590ed7b07c473cabd707fe7/matplotlib-3.8.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: ecd79298550cba13a43c340581a3ec9c707bd895a6a061a78fa2524660482fc0 - requires_dist: - - contourpy >=1.0.1 - - cycler >=0.10 - - fonttools >=4.22.0 - - kiwisolver >=1.3.1 - - numpy >=1.21 - - packaging >=20.0 - - pillow >=8 - - pyparsing >=2.3.1 - - python-dateutil >=2.7 - - importlib-resources >=3.2.0 ; python_version < '3.10' - requires_python: '>=3.9' -- kind: pypi - name: matplotlib-inline - version: 0.1.7 - url: https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl - sha256: df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca - requires_dist: - - traitlets - requires_python: '>=3.8' -- kind: pypi - name: mdurl - version: 0.1.2 - url: https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl - sha256: 84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 - requires_python: '>=3.7' -- kind: pypi - name: mediapy - version: 1.2.0 - url: https://files.pythonhosted.org/packages/1a/26/583ff25923efd88c90733a0fad51890c04e3367663b55548d0c9ed0a658c/mediapy-1.2.0-py3-none-any.whl - sha256: 7b69355d9aa4c513f41a642a9969899dcdc0303c4b20eea0be46a0226fb1fd14 - requires_dist: - - ipython - - matplotlib - - numpy - - pillow - - absl-py ; extra == 'dev' - - pyink ; extra == 'dev' - - pylint >=2.6.0 ; extra == 'dev' - - pytest ; extra == 'dev' - - pytest-xdist ; extra == 'dev' - - pytype ; extra == 'dev' - requires_python: '>=3.8' -- kind: conda - name: metis - version: 5.1.0 - build: h59595ed_1007 - build_number: 1007 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/metis-5.1.0-h59595ed_1007.conda - sha256: 446bf794497284e2ffa28ab9191d70c38d372c51e3fd073f0d8b35efb51e7e02 - md5: 40ccb8318df2500f83bd868dd8fcd201 - depends: - - libgcc-ng >=12 - license: Apache-2.0 - license_family: APACHE - size: 3890263 - timestamp: 1693402645559 -- kind: pypi - name: mistune - version: 3.0.2 - url: https://files.pythonhosted.org/packages/f0/74/c95adcdf032956d9ef6c89a9b8a5152bf73915f8c633f3e3d88d06bd699c/mistune-3.0.2-py3-none-any.whl - sha256: 71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205 - requires_python: '>=3.7' -- kind: conda - name: mkl - version: 2023.0.0 - build: h84fe81f_26648 - build_number: 26648 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/mkl-2023.0.0-h84fe81f_26648.conda - sha256: 989c614ec8417a22f61e9d4ec920c88910bbc3239885a6f20ad4eacad09f277c - md5: 2a37425a272410241c7613c38e3955b2 - depends: - - _openmp_mutex * *_llvm - - _openmp_mutex >=4.5 - - llvm-openmp >=15.0.7 - - tbb 2021.* - license: LicenseRef-ProprietaryIntel - license_family: Proprietary - size: 161440193 - timestamp: 1674673370494 -- kind: conda - name: mpc - version: 1.3.1 - build: hfe3b2da_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/mpc-1.3.1-hfe3b2da_0.conda - sha256: 2f88965949ba7b4b21e7e5facd62285f7c6efdb17359d1b365c3bb4ecc968d29 - md5: 289c71e83dc0daa7d4c81f04180778ca - depends: - - gmp >=6.2.1,<7.0a0 - - libgcc-ng >=12 - - mpfr >=4.1.0,<5.0a0 - license: LGPL-3.0-or-later - license_family: LGPL - size: 116276 - timestamp: 1674263855481 -- kind: conda - name: mpfr - version: 4.2.1 - build: h9458935_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/mpfr-4.2.1-h9458935_1.conda - sha256: 38c501f6b8dff124e57711c01da23e204703a3c14276f4cf6abd28850b2b9893 - md5: 8083b20f566639c22f78bcd6ca35b276 - depends: - - gmp >=6.3.0,<7.0a0 - - libgcc-ng >=12 - license: LGPL-3.0-only - license_family: LGPL - size: 643060 - timestamp: 1712339500544 -- kind: conda - name: mpg123 - version: 1.32.6 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/mpg123-1.32.6-h59595ed_0.conda - sha256: 8895a5ce5122a3b8f59afcba4b032f198e8a690a0efc95ef61f2135357ef0d72 - md5: 9160cdeb523a1b20cf8d2a0bf821f45d - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: LGPL-2.1-only - license_family: LGPL - size: 491811 - timestamp: 1712327176955 -- kind: conda - name: mpmath - version: 1.3.0 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/mpmath-1.3.0-pyhd8ed1ab_0.conda - sha256: a4f025c712ec1502a55c471b56a640eaeebfce38dd497d5a1a33729014cac47a - md5: dbf6e2d89137da32fa6670f3bffc024e - depends: - - python >=3.6 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/mpmath - size: 438339 - timestamp: 1678228210181 -- kind: pypi - name: msgpack - version: 1.0.8 - url: https://files.pythonhosted.org/packages/d9/96/a1868dd8997d65732476dfc70fef44d046c1b4dbe36ec1481ab744d87775/msgpack-1.0.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 00e073efcba9ea99db5acef3959efa45b52bc67b61b00823d2a1a6944bf45982 - requires_python: '>=3.8' -- kind: pypi - name: msgpack-numpy - version: 0.4.8 - url: https://files.pythonhosted.org/packages/9b/5d/f25ac7d4fb77cbd53ddc6d05d833c6bf52b12770a44fa9a447eed470ca9a/msgpack_numpy-0.4.8-py2.py3-none-any.whl - sha256: 773c19d4dfbae1b3c7b791083e2caf66983bb19b40901646f61d8731554ae3da - requires_dist: - - numpy >=1.9.0 - - msgpack >=0.5.2 -- kind: pypi - name: multiprocess - version: 0.70.16 - url: https://files.pythonhosted.org/packages/bc/f7/7ec7fddc92e50714ea3745631f79bd9c96424cb2702632521028e57d3a36/multiprocess-0.70.16-py310-none-any.whl - sha256: c4a9944c67bd49f823687463660a2d6daae94c289adff97e0f9d696ba6371d02 - requires_dist: - - dill >=0.3.8 - requires_python: '>=3.8' -- kind: conda - name: mysql-common - version: 8.3.0 - build: hf1915f5_4 - build_number: 4 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/mysql-common-8.3.0-hf1915f5_4.conda - sha256: 4cf6d29e091398735348550cb74cfd5006e04892d54b6b1ba916935f1af1a151 - md5: 784a4df6676c581ca624fbe460703a6d - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - openssl >=3.2.1,<4.0a0 - license: GPL-2.0-or-later - license_family: GPL - size: 784844 - timestamp: 1709910607121 -- kind: conda - name: mysql-libs - version: 8.3.0 - build: hca2cd23_4 - build_number: 4 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/mysql-libs-8.3.0-hca2cd23_4.conda - sha256: c39cdd1a5829aeffc611f789bdfd4dbd4ce1aa829c73d728defec180b5265d91 - md5: 1b50eebe2a738a3146c154d2eceaa8b6 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - mysql-common 8.3.0 hf1915f5_4 - - openssl >=3.2.1,<4.0a0 - - zstd >=1.5.5,<1.6.0a0 - license: GPL-2.0-or-later - license_family: GPL - size: 1537884 - timestamp: 1709910705541 -- kind: pypi - name: nbclient - version: 0.10.0 - url: https://files.pythonhosted.org/packages/66/e8/00517a23d3eeaed0513e718fbc94aab26eaa1758f5690fc8578839791c79/nbclient-0.10.0-py3-none-any.whl - sha256: f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f - requires_dist: - - jupyter-client >=6.1.12 - - jupyter-core !=5.0.*, >=4.12 - - nbformat >=5.1 - - traitlets >=5.4 - - pre-commit ; extra == 'dev' - - autodoc-traits ; extra == 'docs' - - mock ; extra == 'docs' - - moto ; extra == 'docs' - - myst-parser ; extra == 'docs' - - nbclient[test] ; extra == 'docs' - - sphinx-book-theme ; extra == 'docs' - - sphinx >=1.7 ; extra == 'docs' - - sphinxcontrib-spelling ; extra == 'docs' - - flaky ; extra == 'test' - - ipykernel >=6.19.3 ; extra == 'test' - - ipython ; extra == 'test' - - ipywidgets ; extra == 'test' - - nbconvert >=7.0.0 ; extra == 'test' - - pytest-asyncio ; extra == 'test' - - pytest-cov >=4.0 ; extra == 'test' - - pytest <8, >=7.0 ; extra == 'test' - - testpath ; extra == 'test' - - xmltodict ; extra == 'test' - requires_python: '>=3.8.0' -- kind: pypi - name: nbconvert - version: 7.16.4 - url: https://files.pythonhosted.org/packages/b8/bb/bb5b6a515d1584aa2fd89965b11db6632e4bdc69495a52374bcc36e56cfa/nbconvert-7.16.4-py3-none-any.whl - sha256: 05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3 - requires_dist: - - beautifulsoup4 - - bleach !=5.0.0 - - defusedxml - - importlib-metadata >=3.6 ; python_version < '3.10' - - jinja2 >=3.0 - - jupyter-core >=4.7 - - jupyterlab-pygments - - markupsafe >=2.0 - - mistune <4, >=2.0.3 - - nbclient >=0.5.0 - - nbformat >=5.7 - - packaging - - pandocfilters >=1.4.1 - - pygments >=2.4.1 - - tinycss2 - - traitlets >=5.1 - - flaky ; extra == 'all' - - ipykernel ; extra == 'all' - - ipython ; extra == 'all' - - ipywidgets >=7.5 ; extra == 'all' - - myst-parser ; extra == 'all' - - nbsphinx >=0.2.12 ; extra == 'all' - - playwright ; extra == 'all' - - pydata-sphinx-theme ; extra == 'all' - - pyqtwebengine >=5.15 ; extra == 'all' - - pytest >=7 ; extra == 'all' - - sphinx ==5.0.2 ; extra == 'all' - - sphinxcontrib-spelling ; extra == 'all' - - tornado >=6.1 ; extra == 'all' - - ipykernel ; extra == 'docs' - - ipython ; extra == 'docs' - - myst-parser ; extra == 'docs' - - nbsphinx >=0.2.12 ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinx ==5.0.2 ; extra == 'docs' - - sphinxcontrib-spelling ; extra == 'docs' - - pyqtwebengine >=5.15 ; extra == 'qtpdf' - - pyqtwebengine >=5.15 ; extra == 'qtpng' - - tornado >=6.1 ; extra == 'serve' - - flaky ; extra == 'test' - - ipykernel ; extra == 'test' - - ipywidgets >=7.5 ; extra == 'test' - - pytest >=7 ; extra == 'test' - - playwright ; extra == 'webpdf' - requires_python: '>=3.8' -- kind: pypi - name: nbformat - version: 5.10.4 - url: https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl - sha256: 3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b - requires_dist: - - fastjsonschema >=2.15 - - jsonschema >=2.6 - - jupyter-core !=5.0.*, >=4.12 - - traitlets >=5.1 - - myst-parser ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinx ; extra == 'docs' - - sphinxcontrib-github-alt ; extra == 'docs' - - sphinxcontrib-spelling ; extra == 'docs' - - pep440 ; extra == 'test' - - pre-commit ; extra == 'test' - - pytest ; extra == 'test' - - testpath ; extra == 'test' - requires_python: '>=3.8' -- kind: conda - name: ncurses - version: 6.4.20240210 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.4.20240210-h59595ed_0.conda - sha256: aa0f005b6727aac6507317ed490f0904430584fa8ca722657e7f0fb94741de81 - md5: 97da8860a0da5413c7c98a3b3838a645 - depends: - - libgcc-ng >=12 - license: X11 AND BSD-3-Clause - size: 895669 - timestamp: 1710866638986 -- kind: pypi - name: nerfacc - version: 0.5.2 - url: https://files.pythonhosted.org/packages/f4/16/e93ebb619a3edd8851df21425fe20b7491bd1d819fc19beb9bfc1bf2556e/nerfacc-0.5.2-py3-none-any.whl - sha256: fbc5afb135c9397fafa45132c0615dab8b60be40979911a8a4e829628815bdb7 - requires_dist: - - rich >=12 - - torch - - typing-extensions ; python_version < '3.8' - - black[jupyter] ==22.3.0 ; extra == 'dev' - - isort ==5.10.1 ; extra == 'dev' - - pylint ==2.13.4 ; extra == 'dev' - - pytest ==7.1.2 ; extra == 'dev' - - pytest-xdist ==2.5.0 ; extra == 'dev' - - typeguard >=2.13.3 ; extra == 'dev' - - pyyaml ==6.0 ; extra == 'dev' - - build ; extra == 'dev' - - twine ; extra == 'dev' - requires_python: '>=3.7' -- kind: pypi - name: nerfstudio - version: 1.0.3 - path: . - sha256: 3d33ff5065d6c4e636ad74a6610fdbed41a7f7b143577db98f7c09d2d5776ee9 - requires_dist: - - appdirs >=1.4 - - av >=9.2.0 - - awscli >=1.31.10 - - comet-ml >=3.33.8 - - cryptography >=38 - - tyro >=0.6.6 - - gdown >=4.6.0 - - ninja >=1.10 - - h5py >=2.9.0 - - imageio >=2.21.1 - - ipywidgets >=7.6 - - jaxtyping >=0.2.15 - - jupyterlab >=3.3.4 - - matplotlib >=3.6.0 - - mediapy >=1.1.0 - - msgpack >=1.0.4 - - msgpack-numpy >=0.4.8 - - nerfacc ==0.5.2 - - open3d >=0.16.0 - - opencv-python ==4.8.0.76 - - pillow >=10.3.0 - - plotly >=5.7.0 - - protobuf !=3.20.0, <=3.20.3 - - pyngrok >=5.1.0 - - python-socketio >=5.7.1 - - pyquaternion >=0.9.9 - - requests - - rich >=12.5.1 - - scikit-image >=0.19.3 - - splines ==0.3.0 - - tensorboard >=2.13.0 - - torch >=1.13.1 - - torchvision >=0.14.1 - - torchmetrics[image] >=1.0.1 - - typing-extensions >=4.4.0 - - viser ==0.1.27 - - nuscenes-devkit >=1.1.1 - - wandb >=0.13.3 - - xatlas - - trimesh >=3.20.2 - - timm ==0.6.7 - - gsplat ==1.0.0 - - pytorch-msssim - - pathos - - packaging - - rawpy >=0.18.1 ; platform_machine != 'arm64' - - pymeshlab >=2022.2.post2 ; platform_machine != 'arm64' and platform_machine != 'aarch64' - - newrawpy >=1.0.0b0 ; platform_machine == 'arm64' - - importlib-metadata >=6.0.0 ; python_version < '3.10' - - pre-commit ==3.3.2 ; extra == 'dev' - - pytest ==7.1.2 ; extra == 'dev' - - pytest-xdist ==2.5.0 ; extra == 'dev' - - typeguard ==2.13.3 ; extra == 'dev' - - ruff ==0.1.13 ; extra == 'dev' - - sshconf ==0.2.5 ; extra == 'dev' - - pycolmap >=0.3.0 ; extra == 'dev' - - diffusers ==0.16.1 ; extra == 'dev' - - opencv-stubs ==0.0.7 ; extra == 'dev' - - transformers ==4.29.2 ; extra == 'dev' - - pyright ==1.1.331 ; extra == 'dev' - - torch <2.2, >=1.13.1 ; extra == 'dev' - - projectaria-tools >=1.3.1 ; sys_platform != 'win32' and extra == 'dev' - - furo ==2022.9.29 ; extra == 'docs' - - ipython ==8.6.0 ; extra == 'docs' - - readthedocs-sphinx-search ==0.1.2 ; extra == 'docs' - - myst-nb ==0.16.0 ; extra == 'docs' - - nbconvert ==7.2.5 ; extra == 'docs' - - nbformat ==5.9.2 ; extra == 'docs' - - sphinx ==5.2.1 ; extra == 'docs' - - sphinxemoji ==0.2.0 ; extra == 'docs' - - sphinx-argparse ==0.3.1 ; extra == 'docs' - - sphinx-copybutton ==0.5.0 ; extra == 'docs' - - sphinx-design ==0.2.0 ; extra == 'docs' - - sphinxext-opengraph ==0.6.3 ; extra == 'docs' - - diffusers ==0.16.1 ; extra == 'gen' - - transformers ==4.29.2 ; extra == 'gen' - - accelerate ==0.19.0 ; extra == 'gen' - - bitsandbytes ==0.39.0 ; extra == 'gen' - - sentencepiece ==0.1.99 ; extra == 'gen' - requires_python: '>=3.8.0' - editable: true -- kind: pypi - name: nest-asyncio - version: 1.6.0 - url: https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl - sha256: 87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c - requires_python: '>=3.5' -- kind: conda - name: nettle - version: 3.9.1 - build: h7ab15ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/nettle-3.9.1-h7ab15ed_0.conda - sha256: 1ef1b7efa69c7fb4e2a36a88316f307c115713698d1c12e19f55ae57c0482995 - md5: 2bf1915cc107738811368afcb0993a59 - depends: - - libgcc-ng >=12 - license: GPL 2 and LGPL3 - license_family: GPL - size: 1011638 - timestamp: 1686309814836 -- kind: conda - name: networkx - version: '3.3' - build: pyhd8ed1ab_1 - build_number: 1 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/networkx-3.3-pyhd8ed1ab_1.conda - sha256: cbd8a6de87ad842e7665df38dcec719873fe74698bc761de5431047b8fada41a - md5: d335fd5704b46f4efb89a6774e81aef0 - depends: - - python >=3.10 - constrains: - - pandas >=1.4 - - numpy >=1.22 - - matplotlib >=3.5 - - scipy >=1.9,!=1.11.0,!=1.11.1 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/networkx - size: 1185670 - timestamp: 1712540499262 -- kind: pypi - name: ninja - version: 1.11.1.1 - url: https://files.pythonhosted.org/packages/6d/92/8d7aebd4430ab5ff65df2bfee6d5745f95c004284db2d8ca76dcbfd9de47/ninja-1.11.1.1-py2.py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl - sha256: 84502ec98f02a037a169c4b0d5d86075eaf6afc55e1879003d6cab51ced2ea4b - requires_dist: - - codecov >=2.0.5 ; extra == 'test' - - coverage >=4.2 ; extra == 'test' - - flake8 >=3.0.4 ; extra == 'test' - - pytest >=4.5.0 ; extra == 'test' - - pytest-cov >=2.7.1 ; extra == 'test' - - pytest-runner >=5.1 ; extra == 'test' - - pytest-virtualenv >=1.7.0 ; extra == 'test' - - virtualenv >=15.0.3 ; extra == 'test' -- kind: pypi - name: nodeenv - version: 1.8.0 - url: https://files.pythonhosted.org/packages/1a/e6/6d2ead760a9ddb35e65740fd5a57e46aadd7b0c49861ab24f94812797a1c/nodeenv-1.8.0-py2.py3-none-any.whl - sha256: df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec - requires_dist: - - setuptools - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*' -- kind: pypi - name: notebook - version: 7.0.7 - url: https://files.pythonhosted.org/packages/f2/57/2f8d59ddc7f2d0d8ac4f80f869545bc44646fc78c1c083b3655c58e3edfb/notebook-7.0.7-py3-none-any.whl - sha256: 289b606d7e173f75a18beb1406ef411b43f97f7a9c55ba03efa3622905a62346 - requires_dist: - - jupyter-server <3, >=2.4.0 - - jupyterlab-server <3, >=2.22.1 - - jupyterlab <5, >=4.0.2 - - notebook-shim <0.3, >=0.2 - - tornado >=6.2.0 - - hatch ; extra == 'dev' - - pre-commit ; extra == 'dev' - - myst-parser ; extra == 'docs' - - nbsphinx ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinx >=1.3.6 ; extra == 'docs' - - sphinxcontrib-github-alt ; extra == 'docs' - - sphinxcontrib-spelling ; extra == 'docs' - - importlib-resources >=5.0 ; python_version < '3.10' and extra == 'test' - - ipykernel ; extra == 'test' - - jupyter-server[test] <3, >=2.4.0 ; extra == 'test' - - jupyterlab-server[test] <3, >=2.22.1 ; extra == 'test' - - nbval ; extra == 'test' - - pytest-console-scripts ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest-tornasync ; extra == 'test' - - pytest >=7.0 ; extra == 'test' - - requests ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: notebook-shim - version: 0.2.4 - url: https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl - sha256: 411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef - requires_dist: - - jupyter-server <3, >=1.8 - - pytest ; extra == 'test' - - pytest-console-scripts ; extra == 'test' - - pytest-jupyter ; extra == 'test' - - pytest-tornasync ; extra == 'test' - requires_python: '>=3.7' -- kind: conda - name: nsight-compute - version: 2022.3.0.22 - build: '0' - subdir: linux-64 - url: https://conda.anaconda.org/nvidia/label/cuda-11.8.0/linux-64/nsight-compute-2022.3.0.22-0.tar.bz2 - md5: a438d9120c100bcac9eb166cebdd3023 - arch: x86_64 - platform: linux - size: 639598244 - timestamp: 1661399409484 -- kind: conda - name: nspr - version: '4.35' - build: h27087fc_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/nspr-4.35-h27087fc_0.conda - sha256: 8fadeebb2b7369a4f3b2c039a980d419f65c7b18267ba0c62588f9f894396d0c - md5: da0ec11a6454ae19bff5b02ed881a2b1 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: MPL-2.0 - license_family: MOZILLA - size: 226848 - timestamp: 1669784948267 -- kind: conda - name: nss - version: '3.98' - build: h1d7d5a4_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/nss-3.98-h1d7d5a4_0.conda - sha256: a9bc94d03df48014011cf6caaf447f2ef86a5edf7c70d70002ec4b59f5a4e198 - md5: 54b56c2fdf973656b748e0378900ec13 - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libsqlite >=3.45.1,<4.0a0 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - nspr >=4.35,<5.0a0 - license: MPL-2.0 - license_family: MOZILLA - size: 2019716 - timestamp: 1708065114928 -- kind: conda - name: numpy - version: 1.26.4 - build: py310hb13e2d6_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/numpy-1.26.4-py310hb13e2d6_0.conda - sha256: 028fe2ea8e915a0a032b75165f11747770326f3d767e642880540c60a3256425 - md5: 6593de64c935768b6bad3e19b3e978be - depends: - - libblas >=3.9.0,<4.0a0 - - libcblas >=3.9.0,<4.0a0 - - libgcc-ng >=12 - - liblapack >=3.9.0,<4.0a0 - - libstdcxx-ng >=12 - - python >=3.10,<3.11.0a0 - - python_abi 3.10.* *_cp310 - constrains: - - numpy-base <0a0 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/numpy - size: 7009070 - timestamp: 1707225917496 -- kind: pypi - name: nuscenes-devkit - version: 1.1.9 - url: https://files.pythonhosted.org/packages/c6/53/460bf754677b3b247fb99a447e3575490dbc5f42ec94d528bc0137176f6a/nuscenes_devkit-1.1.9-py3-none-any.whl - sha256: 8a818aaa8566e06960a57d1f88073f5079187bb056dcdab4d6fb54afd63a558c - requires_dist: - - cachetools - - descartes - - fire - - jupyter - - matplotlib - - numpy - - opencv-python - - pillow >6.2.1 - - pyquaternion >=0.9.5 - - scikit-learn - - scipy - - shapely - - tqdm - - pycocotools >=2.0.1 - requires_python: '>=3.6' -- kind: conda - name: ocl-icd - version: 2.3.2 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ocl-icd-2.3.2-hd590300_1.conda - sha256: 0e01384423e48e5011eb6b224da8dc5e3567c87dbcefbe60cd9d5cead276cdcd - md5: c66f837ac65e4d1cdeb80e2a1d5fcc3d - depends: - - libgcc-ng >=12 - license: BSD-2-Clause - license_family: BSD - size: 135681 - timestamp: 1710946531879 -- kind: pypi - name: open3d - version: 0.18.0 - url: https://files.pythonhosted.org/packages/3b/e1/fc609763d982c6c43ee9503279fa6dc42d048b6224a9dc0a0ce8ac19308a/open3d-0.18.0-cp310-cp310-manylinux_2_27_x86_64.whl - sha256: f649d5d58090f73a337895fb0022c7b05c00f47f704b5722b103cceba04cc870 - requires_dist: - - numpy >=1.18.0 - - dash >=2.6.0 - - werkzeug >=2.2.3 - - nbformat >=5.7.0 - - configargparse - - ipywidgets >=8.0.4 - - addict - - pillow >=9.3.0 - - matplotlib >=3 - - numpy >1.18 - - pandas >=1.0 - - pyyaml >=5.4.1 - - scikit-learn >=0.21 - - tqdm - - pyquaternion - - pywinpty ==2.0.2 ; sys_platform == 'win32' and python_version == '3.6' - requires_python: '>=3.8' -- kind: pypi - name: opencv-python - version: 4.8.0.76 - url: https://files.pythonhosted.org/packages/f5/d0/2e455d894ec0d6527e662ad55e70c04f421ad83a6fd0a54c3dd73c411282/opencv_python-4.8.0.76-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 9bcb4944211acf13742dbfd9d3a11dc4e36353ffa1746f2c7dcd6a01c32d1376 - requires_dist: - - numpy >=1.13.3 ; python_version < '3.7' - - numpy >=1.21.0 ; python_version <= '3.9' and platform_system == 'Darwin' and platform_machine == 'arm64' - - numpy >=1.21.2 ; python_version >= '3.10' - - numpy >=1.21.4 ; python_version >= '3.10' and platform_system == 'Darwin' - - numpy >=1.23.5 ; python_version >= '3.11' - - numpy >=1.19.3 ; python_version >= '3.6' and platform_system == 'Linux' and platform_machine == 'aarch64' - - numpy >=1.17.0 ; python_version >= '3.7' - - numpy >=1.17.3 ; python_version >= '3.8' - - numpy >=1.19.3 ; python_version >= '3.9' - requires_python: '>=3.6' -- kind: conda - name: openexr - version: 3.2.2 - build: haf962dd_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/openexr-3.2.2-haf962dd_1.conda - sha256: 01d773a14124929abd6c26169d900ce439f9df8a9e37d3ea197c7f71f61e7906 - md5: 34e58e21fc28e404207d6ce4287da264 - depends: - - imath >=3.1.11,<3.1.12.0a0 - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: BSD-3-Clause - license_family: BSD - size: 1466865 - timestamp: 1709260550301 -- kind: conda - name: openh264 - version: 2.4.1 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/openh264-2.4.1-h59595ed_0.conda - sha256: 0d4eaf15fb771f25c924aef831d76eea11d90c824778fc1e7666346e93475f42 - md5: 3dfcf61b8e78af08110f5229f79580af - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: BSD-2-Clause - license_family: BSD - size: 735244 - timestamp: 1706873814072 -- kind: conda - name: openjpeg - version: 2.5.2 - build: h488ebb8_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.2-h488ebb8_0.conda - sha256: 5600a0b82df042bd27d01e4e687187411561dfc11cc05143a08ce29b64bf2af2 - md5: 7f2e286780f072ed750df46dc2631138 - depends: - - libgcc-ng >=12 - - libpng >=1.6.43,<1.7.0a0 - - libstdcxx-ng >=12 - - libtiff >=4.6.0,<4.7.0a0 - - libzlib >=1.2.13,<1.3.0a0 - license: BSD-2-Clause - license_family: BSD - size: 341592 - timestamp: 1709159244431 -- kind: conda - name: openssl - version: 3.3.0 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.3.0-hd590300_0.conda - sha256: fdbf05e4db88c592366c90bb82e446edbe33c6e49e5130d51c580b2629c0b5d5 - md5: c0f3abb4a16477208bbd43a39bd56f18 - depends: - - ca-certificates - - libgcc-ng >=12 - constrains: - - pyopenssl >=22.1 - license: Apache-2.0 - license_family: Apache - size: 2895187 - timestamp: 1714466138265 -- kind: conda - name: orc - version: 2.0.0 - build: h17fec99_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/orc-2.0.0-h17fec99_1.conda - sha256: ccbfb6c2a01259c2c95b5b8139a0c3a8d4ec6240228ad1ac454b41f5fbcfd082 - md5: d2e0ffa6c3452f0a723a0ef1b96fd1cb - depends: - - libgcc-ng >=12 - - libprotobuf >=4.25.3,<4.25.4.0a0 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - lz4-c >=1.9.3,<1.10.0a0 - - snappy >=1.2.0,<1.3.0a0 - - zstd >=1.5.5,<1.6.0a0 - license: Apache-2.0 - license_family: Apache - size: 1029252 - timestamp: 1712616110941 -- kind: pypi - name: overrides - version: 7.7.0 - url: https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl - sha256: c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49 - requires_dist: - - typing ; python_version < '3.5' - requires_python: '>=3.6' -- kind: conda - name: p11-kit - version: 0.24.1 - build: hc5aa10d_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/p11-kit-0.24.1-hc5aa10d_0.tar.bz2 - sha256: aa8d3887b36557ad0c839e4876c0496e0d670afe843bf5bba4a87764b868196d - md5: 56ee94e34b71742bbdfa832c974e47a8 - depends: - - libffi >=3.4.2,<3.5.0a0 - - libgcc-ng >=12 - - libtasn1 >=4.18.0,<5.0a0 - license: MIT - license_family: MIT - size: 4702497 - timestamp: 1654868759643 -- kind: pypi - name: packaging - version: '24.0' - url: https://files.pythonhosted.org/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl - sha256: 2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 - requires_python: '>=3.7' -- kind: pypi - name: pandas - version: 2.2.2 - url: https://files.pythonhosted.org/packages/89/1b/12521efcbc6058e2673583bb096c2b5046a9df39bd73eca392c1efed24e5/pandas-2.2.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 8635c16bf3d99040fdf3ca3db669a7250ddf49c55dc4aa8fe0ae0fa8d6dcc1f0 - requires_dist: - - numpy >=1.22.4 ; python_version < '3.11' - - numpy >=1.23.2 ; python_version == '3.11' - - numpy >=1.26.0 ; python_version >= '3.12' - - python-dateutil >=2.8.2 - - pytz >=2020.1 - - tzdata >=2022.7 - - hypothesis >=6.46.1 ; extra == 'test' - - pytest >=7.3.2 ; extra == 'test' - - pytest-xdist >=2.2.0 ; extra == 'test' - - pyarrow >=10.0.1 ; extra == 'pyarrow' - - bottleneck >=1.3.6 ; extra == 'performance' - - numba >=0.56.4 ; extra == 'performance' - - numexpr >=2.8.4 ; extra == 'performance' - - scipy >=1.10.0 ; extra == 'computation' - - xarray >=2022.12.0 ; extra == 'computation' - - fsspec >=2022.11.0 ; extra == 'fss' - - s3fs >=2022.11.0 ; extra == 'aws' - - gcsfs >=2022.11.0 ; extra == 'gcp' - - pandas-gbq >=0.19.0 ; extra == 'gcp' - - odfpy >=1.4.1 ; extra == 'excel' - - openpyxl >=3.1.0 ; extra == 'excel' - - python-calamine >=0.1.7 ; extra == 'excel' - - pyxlsb >=1.0.10 ; extra == 'excel' - - xlrd >=2.0.1 ; extra == 'excel' - - xlsxwriter >=3.0.5 ; extra == 'excel' - - pyarrow >=10.0.1 ; extra == 'parquet' - - pyarrow >=10.0.1 ; extra == 'feather' - - tables >=3.8.0 ; extra == 'hdf5' - - pyreadstat >=1.2.0 ; extra == 'spss' - - sqlalchemy >=2.0.0 ; extra == 'postgresql' - - psycopg2 >=2.9.6 ; extra == 'postgresql' - - adbc-driver-postgresql >=0.8.0 ; extra == 'postgresql' - - sqlalchemy >=2.0.0 ; extra == 'mysql' - - pymysql >=1.0.2 ; extra == 'mysql' - - sqlalchemy >=2.0.0 ; extra == 'sql-other' - - adbc-driver-postgresql >=0.8.0 ; extra == 'sql-other' - - adbc-driver-sqlite >=0.8.0 ; extra == 'sql-other' - - beautifulsoup4 >=4.11.2 ; extra == 'html' - - html5lib >=1.1 ; extra == 'html' - - lxml >=4.9.2 ; extra == 'html' - - lxml >=4.9.2 ; extra == 'xml' - - matplotlib >=3.6.3 ; extra == 'plot' - - jinja2 >=3.1.2 ; extra == 'output-formatting' - - tabulate >=0.9.0 ; extra == 'output-formatting' - - pyqt5 >=5.15.9 ; extra == 'clipboard' - - qtpy >=2.3.0 ; extra == 'clipboard' - - zstandard >=0.19.0 ; extra == 'compression' - - dataframe-api-compat >=0.1.7 ; extra == 'consortium-standard' - - adbc-driver-postgresql >=0.8.0 ; extra == 'all' - - adbc-driver-sqlite >=0.8.0 ; extra == 'all' - - beautifulsoup4 >=4.11.2 ; extra == 'all' - - bottleneck >=1.3.6 ; extra == 'all' - - dataframe-api-compat >=0.1.7 ; extra == 'all' - - fastparquet >=2022.12.0 ; extra == 'all' - - fsspec >=2022.11.0 ; extra == 'all' - - gcsfs >=2022.11.0 ; extra == 'all' - - html5lib >=1.1 ; extra == 'all' - - hypothesis >=6.46.1 ; extra == 'all' - - jinja2 >=3.1.2 ; extra == 'all' - - lxml >=4.9.2 ; extra == 'all' - - matplotlib >=3.6.3 ; extra == 'all' - - numba >=0.56.4 ; extra == 'all' - - numexpr >=2.8.4 ; extra == 'all' - - odfpy >=1.4.1 ; extra == 'all' - - openpyxl >=3.1.0 ; extra == 'all' - - pandas-gbq >=0.19.0 ; extra == 'all' - - psycopg2 >=2.9.6 ; extra == 'all' - - pyarrow >=10.0.1 ; extra == 'all' - - pymysql >=1.0.2 ; extra == 'all' - - pyqt5 >=5.15.9 ; extra == 'all' - - pyreadstat >=1.2.0 ; extra == 'all' - - pytest >=7.3.2 ; extra == 'all' - - pytest-xdist >=2.2.0 ; extra == 'all' - - python-calamine >=0.1.7 ; extra == 'all' - - pyxlsb >=1.0.10 ; extra == 'all' - - qtpy >=2.3.0 ; extra == 'all' - - scipy >=1.10.0 ; extra == 'all' - - s3fs >=2022.11.0 ; extra == 'all' - - sqlalchemy >=2.0.0 ; extra == 'all' - - tables >=3.8.0 ; extra == 'all' - - tabulate >=0.9.0 ; extra == 'all' - - xarray >=2022.12.0 ; extra == 'all' - - xlrd >=2.0.1 ; extra == 'all' - - xlsxwriter >=3.0.5 ; extra == 'all' - - zstandard >=0.19.0 ; extra == 'all' - requires_python: '>=3.9' -- kind: pypi - name: pandocfilters - version: 1.5.1 - url: https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl - sha256: 93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*' -- kind: pypi - name: parso - version: 0.8.4 - url: https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl - sha256: a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18 - requires_dist: - - flake8 ==5.0.4 ; extra == 'qa' - - mypy ==0.971 ; extra == 'qa' - - types-setuptools ==67.2.0.1 ; extra == 'qa' - - docopt ; extra == 'testing' - - pytest ; extra == 'testing' - requires_python: '>=3.6' -- kind: pypi - name: pathos - version: 0.3.2 - url: https://files.pythonhosted.org/packages/f4/7f/cea34872c000d17972dad998575d14656d7c6bcf1a08a8d66d73c1ef2cca/pathos-0.3.2-py3-none-any.whl - sha256: d669275e6eb4b3fbcd2846d7a6d1bba315fe23add0c614445ba1408d8b38bafe - requires_dist: - - ppft >=1.7.6.8 - - dill >=0.3.8 - - pox >=0.3.4 - - multiprocess >=0.70.16 - requires_python: '>=3.8' -- kind: conda - name: pcre2 - version: '10.43' - build: hcad00b1_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.43-hcad00b1_0.conda - sha256: 766dd986a7ed6197676c14699000bba2625fd26c8a890fcb7a810e5cf56155bc - md5: 8292dea9e022d9610a11fce5e0896ed8 - depends: - - bzip2 >=1.0.8,<2.0a0 - - libgcc-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: BSD-3-Clause - license_family: BSD - size: 950847 - timestamp: 1708118050286 -- kind: pypi - name: pexpect - version: 4.9.0 - url: https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl - sha256: 7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523 - requires_dist: - - ptyprocess >=0.5 -- kind: conda - name: pillow - version: 10.3.0 - build: py310hf73ecf8_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/pillow-10.3.0-py310hf73ecf8_0.conda - sha256: 89caf2bb9b6d6d0c874590128b36676615750b5ef121fab514bc737dc48534da - md5: 1de56cf017dfd02aa84093206a0141a8 - depends: - - freetype >=2.12.1,<3.0a0 - - lcms2 >=2.16,<3.0a0 - - libgcc-ng >=12 - - libjpeg-turbo >=3.0.0,<4.0a0 - - libtiff >=4.6.0,<4.7.0a0 - - libwebp-base >=1.3.2,<2.0a0 - - libxcb >=1.15,<1.16.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - openjpeg >=2.5.2,<3.0a0 - - python >=3.10,<3.11.0a0 - - python_abi 3.10.* *_cp310 - - tk >=8.6.13,<8.7.0a0 - license: HPND - purls: - - pkg:pypi/pillow - size: 41783273 - timestamp: 1712154626576 -- kind: conda - name: pip - version: '24.0' - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/pip-24.0-pyhd8ed1ab_0.conda - sha256: b7c1c5d8f13e8cb491c4bd1d0d1896a4cf80fc47de01059ad77509112b664a4a - md5: f586ac1e56c8638b64f9c8122a7b8a67 - depends: - - python >=3.7 - - setuptools - - wheel - license: MIT - license_family: MIT - purls: - - pkg:pypi/pip - size: 1398245 - timestamp: 1706960660581 -- kind: conda - name: pixman - version: 0.43.2 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/pixman-0.43.2-h59595ed_0.conda - sha256: 366d28e2a0a191d6c535e234741e0cd1d94d713f76073d8af4a5ccb2a266121e - md5: 71004cbf7924e19c02746ccde9fd7123 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: MIT - license_family: MIT - size: 386826 - timestamp: 1706549500138 -- kind: pypi - name: platformdirs - version: 4.2.1 - url: https://files.pythonhosted.org/packages/b0/15/1691fa5aaddc0c4ea4901c26f6137c29d5f6673596fe960a0340e8c308e1/platformdirs-4.2.1-py3-none-any.whl - sha256: 17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1 - requires_dist: - - furo >=2023.9.10 ; extra == 'docs' - - proselint >=0.13 ; extra == 'docs' - - sphinx-autodoc-typehints >=1.25.2 ; extra == 'docs' - - sphinx >=7.2.6 ; extra == 'docs' - - appdirs ==1.4.4 ; extra == 'test' - - covdefaults >=2.3 ; extra == 'test' - - pytest-cov >=4.1 ; extra == 'test' - - pytest-mock >=3.12 ; extra == 'test' - - pytest >=7.4.3 ; extra == 'test' - - mypy >=1.8 ; extra == 'type' - requires_python: '>=3.8' -- kind: pypi - name: plotly - version: 5.22.0 - url: https://files.pythonhosted.org/packages/0b/f8/b65cdd2be32e442c4efe7b672f73c90b05eab5a7f3f4115efe181d432c60/plotly-5.22.0-py3-none-any.whl - sha256: 68fc1901f098daeb233cc3dd44ec9dc31fb3ca4f4e53189344199c43496ed006 - requires_dist: - - tenacity >=6.2.0 - - packaging - requires_python: '>=3.8' -- kind: pypi - name: pox - version: 0.3.4 - url: https://files.pythonhosted.org/packages/e1/d7/9e73c32f73da71e8224b4cb861b5db50ebdebcdff14d3e3fb47a63c578b2/pox-0.3.4-py3-none-any.whl - sha256: 651b8ae8a7b341b7bfd267f67f63106daeb9805f1ac11f323d5280d2da93fdb6 - requires_python: '>=3.8' -- kind: pypi - name: ppft - version: 1.7.6.8 - url: https://files.pythonhosted.org/packages/ff/fa/5160c7d2fb1d4f2b83cba7a40f0eb4b015b78f6973b7ab6b2e73c233cfdc/ppft-1.7.6.8-py3-none-any.whl - sha256: de2dd4b1b080923dd9627fbdea52649fd741c752fce4f3cf37e26f785df23d9b - requires_dist: - - dill >=0.3.8 ; extra == 'dill' - requires_python: '>=3.8' -- kind: pypi - name: pretty-errors - version: 1.2.25 - url: https://files.pythonhosted.org/packages/6d/8e/2df7467a15eae40e26c476683962fdb810cd1b36676603e2f139b4abbeaf/pretty_errors-1.2.25-py3-none-any.whl - sha256: 8ce68ccd99e0f2a099265c8c1f1c23b7c60a15d69bb08816cb336e237d5dc983 - requires_dist: - - colorama -- kind: pypi - name: prometheus-client - version: 0.20.0 - url: https://files.pythonhosted.org/packages/c7/98/745b810d822103adca2df8decd4c0bbe839ba7ad3511af3f0d09692fc0f0/prometheus_client-0.20.0-py3-none-any.whl - sha256: cde524a85bce83ca359cc837f28b8c0db5cac7aa653a588fd7e84ba061c329e7 - requires_dist: - - twisted ; extra == 'twisted' - requires_python: '>=3.8' -- kind: pypi - name: prompt-toolkit - version: 3.0.43 - url: https://files.pythonhosted.org/packages/ee/fd/ca7bf3869e7caa7a037e23078539467b433a4e01eebd93f77180ab927766/prompt_toolkit-3.0.43-py3-none-any.whl - sha256: a11a29cb3bf0a28a387fe5122cdb649816a957cd9261dcedf8c9f1fef33eacf6 - requires_dist: - - wcwidth - requires_python: '>=3.7.0' -- kind: pypi - name: protobuf - version: 3.20.3 - url: https://files.pythonhosted.org/packages/31/be/80a9c6f16dfa4d41be3edbe655349778ae30882407fa8275eb46b4d34854/protobuf-3.20.3-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl - sha256: 9aae4406ea63d825636cc11ffb34ad3379335803216ee3a856787bcf5ccc751e - requires_python: '>=3.7' -- kind: pypi - name: psutil - version: 5.9.8 - url: https://files.pythonhosted.org/packages/c5/4f/0e22aaa246f96d6ac87fe5ebb9c5a693fbe8877f537a1022527c47ca43c5/psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4 - requires_dist: - - ipaddress ; python_version < '3.0' and extra == 'test' - - mock ; python_version < '3.0' and extra == 'test' - - enum34 ; python_version <= '3.4' and extra == 'test' - - pywin32 ; sys_platform == 'win32' and extra == 'test' - - wmi ; sys_platform == 'win32' and extra == 'test' - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*' -- kind: conda - name: pthread-stubs - version: '0.4' - build: h36c2ea0_1001 - build_number: 1001 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-h36c2ea0_1001.tar.bz2 - sha256: 67c84822f87b641d89df09758da498b2d4558d47b920fd1d3fe6d3a871e000ff - md5: 22dad4df6e8630e8dff2428f6f6a7036 - depends: - - libgcc-ng >=7.5.0 - license: MIT - license_family: MIT - size: 5625 - timestamp: 1606147468727 -- kind: pypi - name: ptyprocess - version: 0.7.0 - url: https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl - sha256: 4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35 -- kind: conda - name: pugixml - version: '1.14' - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/pugixml-1.14-h59595ed_0.conda - sha256: ea5f2d593177318f6b19af05018c953f41124cbb3bf21f9fdedfdb6ac42913ae - md5: 2c97dd90633508b422c11bd3018206ab - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: MIT - license_family: MIT - size: 114871 - timestamp: 1696182708943 -- kind: conda - name: pulseaudio-client - version: '17.0' - build: hb77b528_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/pulseaudio-client-17.0-hb77b528_0.conda - sha256: b27c0c8671bd95c205a61aeeac807c095b60bc76eb5021863f919036d7a964fc - md5: 07f45f1be1c25345faddb8db0de8039b - depends: - - dbus >=1.13.6,<2.0a0 - - libgcc-ng >=12 - - libglib >=2.78.3,<3.0a0 - - libsndfile >=1.2.2,<1.3.0a0 - - libsystemd0 >=255 - constrains: - - pulseaudio 17.0 *_0 - license: LGPL-2.1-or-later - license_family: LGPL - size: 757633 - timestamp: 1705690081905 -- kind: pypi - name: pure-eval - version: 0.2.2 - url: https://files.pythonhosted.org/packages/2b/27/77f9d5684e6bce929f5cfe18d6cfbe5133013c06cb2fbf5933670e60761d/pure_eval-0.2.2-py3-none-any.whl - sha256: 01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350 - requires_dist: - - pytest ; extra == 'tests' -- kind: conda - name: pyarrow - version: 15.0.2 - build: py310hd207890_6_cpu - build_number: 6 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/pyarrow-15.0.2-py310hd207890_6_cpu.conda - sha256: 0fef761f539cbd3a8f145163921e53d3928ebe3953e548d679862c357b580c12 - md5: b00e0408587fecc209714eff65406892 - depends: - - libarrow 15.0.2 hefa796f_6_cpu - - libarrow-acero 15.0.2 hbabe93e_6_cpu - - libarrow-dataset 15.0.2 hbabe93e_6_cpu - - libarrow-flight 15.0.2 hc4f8a93_6_cpu - - libarrow-flight-sql 15.0.2 he4f5ca8_6_cpu - - libarrow-gandiva 15.0.2 hc1954e9_6_cpu - - libarrow-substrait 15.0.2 he4f5ca8_6_cpu - - libgcc-ng >=12 - - libparquet 15.0.2 hacf5a1f_6_cpu - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - - numpy >=1.22.4,<2.0a0 - - python >=3.10,<3.11.0a0 - - python_abi 3.10.* *_cp310 - constrains: - - apache-arrow-proc =*=cpu - license: Apache-2.0 - license_family: APACHE - purls: - - pkg:pypi/pyarrow - size: 4481274 - timestamp: 1714448787064 -- kind: pypi - name: pyasn1 - version: 0.6.0 - url: https://files.pythonhosted.org/packages/23/7e/5f50d07d5e70a2addbccd90ac2950f81d1edd0783630651d9268d7f1db49/pyasn1-0.6.0-py2.py3-none-any.whl - sha256: cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473 - requires_python: '>=3.8' -- kind: pypi - name: pycocotools - version: 2.0.7 - url: https://files.pythonhosted.org/packages/ba/64/0451cf41a00fd5ac4501de4ea0e395b7d909e09d665e56890b5d3809ae26/pycocotools-2.0.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 9eb5d46900375adaba88eedb5cbc29d8cbcf43e82505d67378df1c3b720a8c5f - requires_dist: - - matplotlib >=2.1.0 - - numpy - requires_python: '>=3.5' -- kind: pypi - name: pycollada - version: '0.8' - url: https://files.pythonhosted.org/packages/dc/f1/5e81108414287278a01f1642271d7885e2aebc2bd10e7cf744d8c4cf0955/pycollada-0.8.tar.gz - sha256: f3a3759cc4cec1d59e932aad74399dbcf541d18862aad903c770040da42af20e - requires_dist: - - python-dateutil >=2.2 - - numpy - - lxml ; extra == 'prettyprint' - - lxml ; extra == 'validation' -- kind: pypi - name: pycparser - version: '2.22' - url: https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl - sha256: c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc - requires_python: '>=3.8' -- kind: pypi - name: pygments - version: 2.18.0 - url: https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl - sha256: b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a - requires_dist: - - colorama >=0.4.6 ; extra == 'windows-terminal' - requires_python: '>=3.8' -- kind: pypi - name: pyliblzfse - version: 0.4.1 - url: https://files.pythonhosted.org/packages/2c/ba/a4bc465d36f6aafbff89da1bf67bcc6a97475b1d2300a74a778dcb293cef/pyliblzfse-0.4.1.tar.gz - sha256: bb0b899b3830c02fdf3dbde48ea59611833f366fef836e5c32cf8145134b7d3d -- kind: pypi - name: pymeshlab - version: 2022.2.post3 - url: https://files.pythonhosted.org/packages/44/b2/5e98847b924748ec293bac6a68bb7d203a9ec328dbf7ef9fb886fd0e2c07/pymeshlab-2022.2.post3-cp310-cp310-manylinux1_x86_64.whl - sha256: b329ce9d42eec47bd3262c61d50d3e29e2b19defe3cb981e9ed0c0b14d7a1393 - requires_dist: - - numpy -- kind: pypi - name: pyngrok - version: 7.1.6 - url: https://files.pythonhosted.org/packages/cb/55/68b89d526e8331724665dcded0a32a76d73d6bcac41cc56084fda8e25486/pyngrok-7.1.6-py3-none-any.whl - sha256: 422ac7c339622fef51308f0c493a1f5a05d0f403eee5bdd183fb4021a6cb90d4 - requires_dist: - - pyyaml >=5.1 - - coverage[toml] ; extra == 'dev' - - psutil ; extra == 'dev' - - flake8 ; extra == 'dev' - - flake8-pyproject ; extra == 'dev' - - pep8-naming ; extra == 'dev' - - sphinx ; extra == 'docs' - - sphinx-notfound-page ; extra == 'docs' - - sphinx-autodoc-typehints ==1.25.2 ; extra == 'docs' - - sphinx-substitution-extensions ; extra == 'docs' - - mypy ; extra == 'docs' - - types-pyyaml ; extra == 'docs' - requires_python: '>=3.8' -- kind: pypi - name: pyparsing - version: 3.1.2 - url: https://files.pythonhosted.org/packages/9d/ea/6d76df31432a0e6fdf81681a895f009a4bb47b3c39036db3e1b528191d52/pyparsing-3.1.2-py3-none-any.whl - sha256: f9db75911801ed778fe61bb643079ff86601aca99fcae6345aa67292038fb742 - requires_dist: - - railroad-diagrams ; extra == 'diagrams' - - jinja2 ; extra == 'diagrams' - requires_python: '>=3.6.8' -- kind: pypi - name: pyquaternion - version: 0.9.9 - url: https://files.pythonhosted.org/packages/49/b3/d8482e8cacc8ea15a356efea13d22ce1c5914a9ee36622ba250523240bf2/pyquaternion-0.9.9-py3-none-any.whl - sha256: e65f6e3f7b1fdf1a9e23f82434334a1ae84f14223eee835190cd2e841f8172ec - requires_dist: - - numpy - - mkdocs ; extra == 'dev' - - nose ; extra == 'test' -- kind: conda - name: pysocks - version: 1.7.1 - build: pyha2e5f31_6 - build_number: 6 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2 - sha256: a42f826e958a8d22e65b3394f437af7332610e43ee313393d1cf143f0a2d274b - md5: 2a7de29fb590ca14b5243c4c812c8025 - depends: - - __unix - - python >=3.8 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/pysocks - size: 18981 - timestamp: 1661604969727 -- kind: conda - name: python - version: 3.10.14 - build: hd12c33a_0_cpython - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/python-3.10.14-hd12c33a_0_cpython.conda - sha256: 76a5d12e73542678b70a94570f7b0f7763f9a938f77f0e75d9ea615ef22aa84c - md5: 2b4ba962994e8bd4be9ff5b64b75aff2 - depends: - - bzip2 >=1.0.8,<2.0a0 - - ld_impl_linux-64 >=2.36.1 - - libffi >=3.4,<4.0a0 - - libgcc-ng >=12 - - libnsl >=2.0.1,<2.1.0a0 - - libsqlite >=3.45.2,<4.0a0 - - libuuid >=2.38.1,<3.0a0 - - libxcrypt >=4.4.36 - - libzlib >=1.2.13,<1.3.0a0 - - ncurses >=6.4.20240210,<7.0a0 - - openssl >=3.2.1,<4.0a0 - - readline >=8.2,<9.0a0 - - tk >=8.6.13,<8.7.0a0 - - tzdata - - xz >=5.2.6,<6.0a0 - constrains: - - python_abi 3.10.* *_cp310 - license: Python-2.0 - size: 25517742 - timestamp: 1710939725109 -- kind: pypi - name: python-box - version: 6.1.0 - url: https://files.pythonhosted.org/packages/6f/32/3c865e7d62e481c46abffef3303db0d27bf2ca72e4f497d05d66939bfd4a/python_box-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: ab13208b053525ef154a36a4a52873b98a12b18b946edd4c939a4d5080e9a218 - requires_dist: - - pyyaml ; extra == 'pyyaml' - - ruamel-yaml >=0.17 ; extra == 'all' - - toml ; extra == 'all' - - msgpack ; extra == 'all' - - msgpack ; extra == 'msgpack' - - ruamel-yaml >=0.17 ; extra == 'ruamel.yaml' - - toml ; extra == 'toml' - - tomli-w ; extra == 'tomli' - - tomli ; python_version < '3.11' and extra == 'tomli' - - ruamel-yaml >=0.17 ; extra == 'yaml' - requires_python: '>=3.7' -- kind: pypi - name: python-dateutil - version: 2.9.0.post0 - url: https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl - sha256: a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427 - requires_dist: - - six >=1.5 - requires_python: '!=3.0.*,!=3.1.*,!=3.2.*,>=2.7' -- kind: pypi - name: python-engineio - version: 4.9.0 - url: https://files.pythonhosted.org/packages/fe/e5/03fa8e76c718e1dd7fb5b74e9ce816ae0e08734080b1e98dbafbcf2fc8ba/python_engineio-4.9.0-py3-none-any.whl - sha256: 979859bff770725b75e60353d7ae53b397e8b517d05ba76733b404a3dcca3e4c - requires_dist: - - simple-websocket >=0.10.0 - - aiohttp >=3.4 ; extra == 'asyncio_client' - - requests >=2.21.0 ; extra == 'client' - - websocket-client >=0.54.0 ; extra == 'client' - - sphinx ; extra == 'docs' - requires_python: '>=3.6' -- kind: pypi - name: python-json-logger - version: 2.0.7 - url: https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl - sha256: f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd - requires_python: '>=3.6' -- kind: pypi - name: python-socketio - version: 5.11.2 - url: https://files.pythonhosted.org/packages/af/bf/be12875b17709b591d8505811e513a88b31316e4ce0e801da351b4765ea5/python_socketio-5.11.2-py3-none-any.whl - sha256: b9f22a8ff762d7a6e123d16a43ddb1a27d50f07c3c88ea999334f2f89b0ad52b - requires_dist: - - bidict >=0.21.0 - - python-engineio >=4.8.0 - - aiohttp >=3.4 ; extra == 'asyncio_client' - - requests >=2.21.0 ; extra == 'client' - - websocket-client >=0.54.0 ; extra == 'client' - - sphinx ; extra == 'docs' - requires_python: '>=3.8' -- kind: conda - name: python_abi - version: '3.10' - build: 4_cp310 - build_number: 4 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/python_abi-3.10-4_cp310.conda - sha256: 456bec815bfc2b364763084d08b412fdc4c17eb9ccc66a36cb775fa7ac3cbaec - md5: 26322ec5d7712c3ded99dd656142b8ce - constrains: - - python 3.10.* *_cpython - license: BSD-3-Clause - license_family: BSD - size: 6398 - timestamp: 1695147363189 -- kind: conda - name: pytorch - version: 2.2.2 - build: py3.10_cuda11.8_cudnn8.7.0_0 - subdir: linux-64 - url: https://conda.anaconda.org/pytorch/linux-64/pytorch-2.2.2-py3.10_cuda11.8_cudnn8.7.0_0.tar.bz2 - sha256: b5ade394eae124c0e57f602b789f94def2c2a9eea1556c6ee13fc354ed7e6212 - md5: 9b4b26675d6cea4197f0b680752a784d - depends: - - blas * mkl - - filelock - - jinja2 - - llvm-openmp <16 - - mkl >=2018 - - networkx - - python >=3.10,<3.11.0a0 - - pytorch-cuda >=11.8,<11.9 - - pytorch-mutex 1.0 cuda - - pyyaml - - sympy - - torchtriton 2.2.0 - - typing_extensions - constrains: - - cpuonly <0 - license: BSD 3-Clause - license_family: BSD - purls: - - pkg:pypi/torch - size: 1633315666 - timestamp: 1711411702923 -- kind: conda - name: pytorch-cuda - version: '11.8' - build: h7e8668a_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/pytorch/linux-64/pytorch-cuda-11.8-h7e8668a_5.tar.bz2 - sha256: 81a9df218f84b45386818dbc180180a5adb7a5df097d1c4c7ec05c5fa5b0f8ca - md5: 48e990086eb245cce92f09b45a34651e - depends: - - cuda-cudart >=11.8,<12.0 - - cuda-cupti >=11.8,<12.0 - - cuda-libraries >=11.8,<12.0 - - cuda-nvrtc >=11.8,<12.0 - - cuda-nvtx >=11.8,<12.0 - - cuda-runtime >=11.8,<12.0 - - libcublas >=11.11.3.6,<12.0.1.189 - - libcufft >=10.9.0.58,<11.0.0.21 - - libcusolver >=11.4.1.48,<11.4.2.57 - - libcusparse >=11.7.5.86,<12.0.0.76 - - libnpp >=11.8.0.86,<12.0.0.30 - - libnvjpeg >=11.9.0.86,<12.0.0.28 - size: 3561 - timestamp: 1682528151734 -- kind: pypi - name: pytorch-msssim - version: 1.0.0 - url: https://files.pythonhosted.org/packages/e2/8c/856047f955acc30179e9255fdc488059ca22f0938519523d53494f7cfee8/pytorch_msssim-1.0.0-py3-none-any.whl - sha256: 0b4b7bbf7035fe9dc8084244237aac13b1f104852c45b63a7e9fab4363bede54 - requires_dist: - - torch -- kind: conda - name: pytorch-mutex - version: '1.0' - build: cuda - build_number: 100 - subdir: noarch - noarch: generic - url: https://conda.anaconda.org/pytorch/noarch/pytorch-mutex-1.0-cuda.tar.bz2 - sha256: c16316183f51b74ca5eee4dcb8631052f328c0bbf244176734a0b7d390b81ee3 - md5: a948316e36fb5b11223b3fcfa93f8358 - size: 2906 - timestamp: 1628062930777 -- kind: pypi - name: pytz - version: '2024.1' - url: https://files.pythonhosted.org/packages/9c/3d/a121f284241f08268b21359bd425f7d4825cffc5ac5cd0e1b3d82ffd2b10/pytz-2024.1-py2.py3-none-any.whl - sha256: 328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319 -- kind: conda - name: pyyaml - version: 6.0.1 - build: py310h2372a71_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.1-py310h2372a71_1.conda - sha256: aa78ccddb0a75fa722f0f0eb3537c73ee1219c9dd46cea99d6b9eebfdd780f3d - md5: bb010e368de4940771368bc3dc4c63e7 - depends: - - libgcc-ng >=12 - - python >=3.10,<3.11.0a0 - - python_abi 3.10.* *_cp310 - - yaml >=0.2.5,<0.3.0a0 - license: MIT - license_family: MIT - purls: - - pkg:pypi/pyyaml - size: 170627 - timestamp: 1695373587159 -- kind: pypi - name: pyzmq - version: 26.0.3 - url: https://files.pythonhosted.org/packages/40/4f/088d0fe18b188a0754483b7d632a97ef608dce80c2648219d071c9f1715c/pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl - sha256: ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf - requires_dist: - - cffi ; implementation_name == 'pypy' - requires_python: '>=3.7' -- kind: conda - name: qt-main - version: 5.15.8 - build: hc9dc06e_21 - build_number: 21 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/qt-main-5.15.8-hc9dc06e_21.conda - sha256: 6b4594f6f2fad65a7ed52993f602e3ab183193755fe4a492aaa48e463b23105b - md5: b325046180590c868ce0dbf267b82eb8 - depends: - - __glibc >=2.17,<3.0.a0 - - alsa-lib >=1.2.11,<1.3.0a0 - - dbus >=1.13.6,<2.0a0 - - fontconfig >=2.14.2,<3.0a0 - - fonts-conda-ecosystem - - freetype >=2.12.1,<3.0a0 - - gst-plugins-base >=1.24.1,<1.25.0a0 - - gstreamer >=1.24.1,<1.25.0a0 - - harfbuzz >=8.3.0,<9.0a0 - - icu >=73.2,<74.0a0 - - krb5 >=1.21.2,<1.22.0a0 - - libclang-cpp15 >=15.0.7,<15.1.0a0 - - libclang13 >=15.0.7 - - libcups >=2.3.3,<2.4.0a0 - - libevent >=2.1.12,<2.1.13.0a0 - - libexpat >=2.6.2,<3.0a0 - - libgcc-ng >=12 - - libglib >=2.80.0,<3.0a0 - - libjpeg-turbo >=3.0.0,<4.0a0 - - libllvm15 >=15.0.7,<15.1.0a0 - - libpng >=1.6.43,<1.7.0a0 - - libpq >=16.2,<17.0a0 - - libsqlite >=3.45.2,<4.0a0 - - libstdcxx-ng >=12 - - libxcb >=1.15,<1.16.0a0 - - libxkbcommon >=1.7.0,<2.0a0 - - libxml2 >=2.12.6,<3.0a0 - - libzlib >=1.2.13,<1.3.0a0 - - mysql-libs >=8.3.0,<8.4.0a0 - - nspr >=4.35,<5.0a0 - - nss >=3.98,<4.0a0 - - openssl >=3.2.1,<4.0a0 - - pulseaudio-client >=17.0,<17.1.0a0 - - xcb-util >=0.4.0,<0.5.0a0 - - xcb-util-image >=0.4.0,<0.5.0a0 - - xcb-util-keysyms >=0.4.0,<0.5.0a0 - - xcb-util-renderutil >=0.3.9,<0.4.0a0 - - xcb-util-wm >=0.4.1,<0.5.0a0 - - xorg-libice >=1.1.1,<2.0a0 - - xorg-libsm >=1.2.4,<2.0a0 - - xorg-libx11 >=1.8.9,<2.0a0 - - xorg-libxext >=1.3.4,<2.0a0 - - xorg-xf86vidmodeproto - - zstd >=1.5.5,<1.6.0a0 - constrains: - - qt 5.15.8 - license: LGPL-3.0-only - license_family: LGPL - size: 61305384 - timestamp: 1712549380352 -- kind: pypi - name: qtconsole - version: 5.5.2 - url: https://files.pythonhosted.org/packages/f2/3f/de5e5eb44900c1ed1c1567bc505e3b6e6f4c01cf29e558bf2f8cee29af5b/qtconsole-5.5.2-py3-none-any.whl - sha256: 42d745f3d05d36240244a04e1e1ec2a86d5d9b6edb16dbdef582ccb629e87e0b - requires_dist: - - traitlets !=5.2.1, !=5.2.2 - - jupyter-core - - jupyter-client >=4.1 - - pygments - - ipykernel >=4.1 - - qtpy >=2.4.0 - - pyzmq >=17.1 - - packaging - - sphinx >=1.3 ; extra == 'doc' - - flaky ; extra == 'test' - - pytest ; extra == 'test' - - pytest-qt ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: qtpy - version: 2.4.1 - url: https://files.pythonhosted.org/packages/7e/a9/2146d5117ad8a81185331e0809a6b48933c10171f5bac253c6df9fce991c/QtPy-2.4.1-py3-none-any.whl - sha256: 1c1d8c4fa2c884ae742b069151b0abe15b3f70491f3972698c683b8e38de839b - requires_dist: - - packaging - - pytest !=7.0.0, !=7.0.1, >=6 ; extra == 'test' - - pytest-cov >=3.0.0 ; extra == 'test' - - pytest-qt ; extra == 'test' - requires_python: '>=3.7' -- kind: pypi - name: rawpy - version: 0.21.0 - url: https://files.pythonhosted.org/packages/72/2f/80c24a0f24c3a8ae2a9b8cfb579bba0ddcdef9bfd420b98ce69a51b754d2/rawpy-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: d6915760945ca058b9b1b2184459a862baa33b70e53abeb165d2f3d779eb7a78 - requires_dist: - - numpy -- kind: conda - name: rdma-core - version: '51.0' - build: hd3aeb46_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/rdma-core-51.0-hd3aeb46_0.conda - sha256: bcc774b60605b09701cfad41b2d6d9c3f052dd4adfc1f02bf1c929076f48fe30 - md5: 493598e1f28c01e316fda127715593aa - depends: - - __glibc >=2.17,<3.0.a0 - - libgcc-ng >=12 - - libnl >=3.9.0,<4.0a0 - - libstdcxx-ng >=12 - license: Linux-OpenIB - license_family: BSD - size: 4734659 - timestamp: 1711958296706 -- kind: conda - name: re2 - version: 2023.09.01 - build: h7f4b329_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/re2-2023.09.01-h7f4b329_2.conda - sha256: f0f520f57e6b58313e8c41abc7dfa48742a05f1681f05654558127b667c769a8 - md5: 8f70e36268dea8eb666ef14c29bd3cda - depends: - - libre2-11 2023.09.01 h5a48ba9_2 - license: BSD-3-Clause - license_family: BSD - size: 26617 - timestamp: 1708946796423 -- kind: conda - name: readline - version: '8.2' - build: h8228510_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda - sha256: 5435cf39d039387fbdc977b0a762357ea909a7694d9528ab40f005e9208744d7 - md5: 47d31b792659ce70f470b5c82fdfb7a4 - depends: - - libgcc-ng >=12 - - ncurses >=6.3,<7.0a0 - license: GPL-3.0-only - license_family: GPL - size: 281456 - timestamp: 1679532220005 -- kind: pypi - name: referencing - version: 0.35.1 - url: https://files.pythonhosted.org/packages/b7/59/2056f61236782a2c86b33906c025d4f4a0b17be0161b63b70fd9e8775d36/referencing-0.35.1-py3-none-any.whl - sha256: eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de - requires_dist: - - attrs >=22.2.0 - - rpds-py >=0.7.0 - requires_python: '>=3.8' -- kind: conda - name: requests - version: 2.31.0 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/requests-2.31.0-pyhd8ed1ab_0.conda - sha256: 9f629d6fd3c8ac5f2a198639fe7af87c4db2ac9235279164bfe0fcb49d8c4bad - md5: a30144e4156cdbb236f99ebb49828f8b - depends: - - certifi >=2017.4.17 - - charset-normalizer >=2,<4 - - idna >=2.5,<4 - - python >=3.7 - - urllib3 >=1.21.1,<3 - constrains: - - chardet >=3.0.2,<6 - license: Apache-2.0 - license_family: APACHE - purls: - - pkg:pypi/requests - size: 56690 - timestamp: 1684774408600 -- kind: pypi - name: requests-toolbelt - version: 1.0.0 - url: https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl - sha256: cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06 - requires_dist: - - requests <3.0.0, >=2.0.1 - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*' -- kind: pypi - name: retrying - version: 1.3.4 - url: https://files.pythonhosted.org/packages/8f/04/9e36f28be4c0532c0e9207ff9dc01fb13a2b0eb036476a213b0000837d0e/retrying-1.3.4-py3-none-any.whl - sha256: 8cc4d43cb8e1125e0ff3344e9de678fefd85db3b750b81b2240dc0183af37b35 - requires_dist: - - six >=1.7.0 -- kind: pypi - name: rfc3339-validator - version: 0.1.4 - url: https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl - sha256: 24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa - requires_dist: - - six - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' -- kind: pypi - name: rfc3986-validator - version: 0.1.1 - url: https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl - sha256: 2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9 - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*' -- kind: pypi - name: rich - version: 13.7.1 - url: https://files.pythonhosted.org/packages/87/67/a37f6214d0e9fe57f6ae54b2956d550ca8365857f42a1ce0392bb21d9410/rich-13.7.1-py3-none-any.whl - sha256: 4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 - requires_dist: - - ipywidgets >=7.5.1, <9 ; extra == 'jupyter' - - markdown-it-py >=2.2.0 - - pygments >=2.13.0, <3.0.0 - - typing-extensions >=4.0.0, <5.0 ; python_version < '3.9' - requires_python: '>=3.7.0' -- kind: pypi - name: rpds-py - version: 0.18.1 - url: https://files.pythonhosted.org/packages/e5/20/10c12b1acb102c4981a7e1dc86b60e36c1d5c940a7bda48643542f80dbff/rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0 - requires_python: '>=3.8' -- kind: pypi - name: rsa - version: 4.7.2 - url: https://files.pythonhosted.org/packages/e9/93/0c0f002031f18b53af7a6166103c02b9c0667be528944137cc954ec921b3/rsa-4.7.2-py3-none-any.whl - sha256: 78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2 - requires_dist: - - pyasn1 >=0.1.3 - requires_python: '>=3.5,<4' -- kind: pypi - name: rtree - version: 1.2.0 - url: https://files.pythonhosted.org/packages/59/a5/176d27468a1b0bcd7fa9c011cadacfa364e9bca8fa649baab7fb3f15af70/Rtree-1.2.0-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl - sha256: 613f2158aeba6fcb5e4aa4c076bb6de85e20c4f9fb0a8b426a71d6ff5846795b - requires_python: '>=3.8' -- kind: conda - name: s2n - version: 1.4.12 - build: h06160fa_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/s2n-1.4.12-h06160fa_0.conda - sha256: fc5759c4d8136bb9048ed5cd2e8fd1a375104c3a7ec60fee1be0b06e7487d610 - md5: bf1899cfd6dea061a220fa7e96a1f4bd - depends: - - libgcc-ng >=12 - - openssl >=3.2.1,<4.0a0 - license: Apache-2.0 - license_family: Apache - size: 346689 - timestamp: 1713325107791 -- kind: pypi - name: s3transfer - version: 0.10.1 - url: https://files.pythonhosted.org/packages/83/37/395cdb6ee92925fa211e55d8f07b9f93cf93f60d7d4ce5e66fd73f1ea986/s3transfer-0.10.1-py3-none-any.whl - sha256: ceb252b11bcf87080fb7850a224fb6e05c8a776bab8f2b64b7f25b969464839d - requires_dist: - - botocore <2.0a0, >=1.33.2 - - botocore[crt] <2.0a0, >=1.33.2 ; extra == 'crt' - requires_python: '>=3.8' -- kind: pypi - name: scikit-image - version: 0.23.2 - url: https://files.pythonhosted.org/packages/ea/82/264b5d0f2f4c4ec073e59dd1ac1ed5fa85f54bec2dd4cc231fcdfd12ba42/scikit_image-0.23.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 08b10781efbd6b084f3c847ff4049b657241ea866b9e331b14bf791dcb3e6661 - requires_dist: - - numpy >=1.23 - - scipy >=1.9 - - networkx >=2.8 - - pillow >=9.1 - - imageio >=2.33 - - tifffile >=2022.8.12 - - packaging >=21 - - lazy-loader >=0.4 - - meson-python >=0.15 ; extra == 'build' - - wheel ; extra == 'build' - - setuptools >=67 ; extra == 'build' - - packaging >=21 ; extra == 'build' - - ninja ; extra == 'build' - - cython >=3.0.4 ; extra == 'build' - - pythran ; extra == 'build' - - numpy >=2.0.0rc1 ; extra == 'build' - - spin ==0.8 ; extra == 'build' - - build ; extra == 'build' - - pooch >=1.6.0 ; extra == 'data' - - pre-commit ; extra == 'developer' - - ipython ; extra == 'developer' - - tomli ; python_version < '3.11' and extra == 'developer' - - sphinx >=7.3 ; extra == 'docs' - - sphinx-gallery >=0.14 ; extra == 'docs' - - numpydoc >=1.7 ; extra == 'docs' - - sphinx-copybutton ; extra == 'docs' - - pytest-runner ; extra == 'docs' - - matplotlib >=3.6 ; extra == 'docs' - - dask[array] >=2022.9.2 ; extra == 'docs' - - pandas >=1.5 ; extra == 'docs' - - seaborn >=0.11 ; extra == 'docs' - - pooch >=1.6 ; extra == 'docs' - - tifffile >=2022.8.12 ; extra == 'docs' - - myst-parser ; extra == 'docs' - - ipywidgets ; extra == 'docs' - - ipykernel ; extra == 'docs' - - plotly >=5.10 ; extra == 'docs' - - kaleido ; extra == 'docs' - - scikit-learn >=1.1 ; extra == 'docs' - - sphinx-design >=0.5 ; extra == 'docs' - - pydata-sphinx-theme >=0.15.2 ; extra == 'docs' - - pywavelets >=1.1.1 ; extra == 'docs' - - pytest-doctestplus ; extra == 'docs' - - simpleitk ; extra == 'optional' - - astropy >=5.0 ; extra == 'optional' - - cloudpickle >=0.2.1 ; extra == 'optional' - - dask[array] >=2021.1.0 ; extra == 'optional' - - matplotlib >=3.6 ; extra == 'optional' - - pooch >=1.6.0 ; extra == 'optional' - - pyamg ; extra == 'optional' - - pywavelets >=1.1.1 ; extra == 'optional' - - scikit-learn >=1.1 ; extra == 'optional' - - asv ; extra == 'test' - - numpydoc >=1.7 ; extra == 'test' - - pooch >=1.6.0 ; extra == 'test' - - pytest >=7.0 ; extra == 'test' - - pytest-cov >=2.11.0 ; extra == 'test' - - pytest-localserver ; extra == 'test' - - pytest-faulthandler ; extra == 'test' - - pytest-doctestplus ; extra == 'test' - requires_python: '>=3.10' -- kind: pypi - name: scikit-learn - version: 1.4.2 - url: https://files.pythonhosted.org/packages/8f/38/420ee614359d8f453ffe2bb5c2e963bf50459d9bbd3f5a92aa9059658955/scikit_learn-1.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 36f0ea5d0f693cb247a073d21a4123bdf4172e470e6d163c12b74cbb1536cf38 - requires_dist: - - numpy >=1.19.5 - - scipy >=1.6.0 - - joblib >=1.2.0 - - threadpoolctl >=2.0.0 - - matplotlib >=3.3.4 ; extra == 'benchmark' - - pandas >=1.1.5 ; extra == 'benchmark' - - memory-profiler >=0.57.0 ; extra == 'benchmark' - - matplotlib >=3.3.4 ; extra == 'docs' - - scikit-image >=0.17.2 ; extra == 'docs' - - pandas >=1.1.5 ; extra == 'docs' - - seaborn >=0.9.0 ; extra == 'docs' - - memory-profiler >=0.57.0 ; extra == 'docs' - - sphinx >=6.0.0 ; extra == 'docs' - - sphinx-copybutton >=0.5.2 ; extra == 'docs' - - sphinx-gallery >=0.15.0 ; extra == 'docs' - - numpydoc >=1.2.0 ; extra == 'docs' - - pillow >=7.1.2 ; extra == 'docs' - - pooch >=1.6.0 ; extra == 'docs' - - sphinx-prompt >=1.3.0 ; extra == 'docs' - - sphinxext-opengraph >=0.4.2 ; extra == 'docs' - - plotly >=5.14.0 ; extra == 'docs' - - matplotlib >=3.3.4 ; extra == 'examples' - - scikit-image >=0.17.2 ; extra == 'examples' - - pandas >=1.1.5 ; extra == 'examples' - - seaborn >=0.9.0 ; extra == 'examples' - - pooch >=1.6.0 ; extra == 'examples' - - plotly >=5.14.0 ; extra == 'examples' - - matplotlib >=3.3.4 ; extra == 'tests' - - scikit-image >=0.17.2 ; extra == 'tests' - - pandas >=1.1.5 ; extra == 'tests' - - pytest >=7.1.2 ; extra == 'tests' - - pytest-cov >=2.9.0 ; extra == 'tests' - - ruff >=0.0.272 ; extra == 'tests' - - black >=23.3.0 ; extra == 'tests' - - mypy >=1.3 ; extra == 'tests' - - pyamg >=4.0.0 ; extra == 'tests' - - polars >=0.19.12 ; extra == 'tests' - - pyarrow >=12.0.0 ; extra == 'tests' - - numpydoc >=1.2.0 ; extra == 'tests' - - pooch >=1.6.0 ; extra == 'tests' - requires_python: '>=3.9' -- kind: pypi - name: scipy - version: 1.13.0 - url: https://files.pythonhosted.org/packages/b9/9d/39dbcf49a793157f9d4f5b8961855677eb4dbb4b82700dcee7042ad2310c/scipy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: b8434f6f3fa49f631fae84afee424e2483289dfc30a47755b4b4e6b07b2633a4 - requires_dist: - - numpy <2.3, >=1.22.4 - - pytest ; extra == 'test' - - pytest-cov ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest-xdist ; extra == 'test' - - asv ; extra == 'test' - - mpmath ; extra == 'test' - - gmpy2 ; extra == 'test' - - threadpoolctl ; extra == 'test' - - scikit-umfpack ; extra == 'test' - - pooch ; extra == 'test' - - hypothesis >=6.30 ; extra == 'test' - - array-api-strict ; extra == 'test' - - sphinx >=5.0.0 ; extra == 'doc' - - pydata-sphinx-theme >=0.15.2 ; extra == 'doc' - - sphinx-design >=0.4.0 ; extra == 'doc' - - matplotlib >=3.5 ; extra == 'doc' - - numpydoc ; extra == 'doc' - - jupytext ; extra == 'doc' - - myst-nb ; extra == 'doc' - - pooch ; extra == 'doc' - - jupyterlite-sphinx >=0.12.0 ; extra == 'doc' - - jupyterlite-pyodide-kernel ; extra == 'doc' - - mypy ; extra == 'dev' - - typing-extensions ; extra == 'dev' - - types-psutil ; extra == 'dev' - - pycodestyle ; extra == 'dev' - - ruff ; extra == 'dev' - - cython-lint >=0.12.2 ; extra == 'dev' - - rich-click ; extra == 'dev' - - doit >=0.36.0 ; extra == 'dev' - - pydevtool ; extra == 'dev' - requires_python: '>=3.9' -- kind: pypi - name: semantic-version - version: 2.10.0 - url: https://files.pythonhosted.org/packages/6a/23/8146aad7d88f4fcb3a6218f41a60f6c2d4e3a72de72da1825dc7c8f7877c/semantic_version-2.10.0-py2.py3-none-any.whl - sha256: de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177 - requires_dist: - - django >=1.11 ; extra == 'dev' - - nose2 ; extra == 'dev' - - tox ; extra == 'dev' - - check-manifest ; extra == 'dev' - - coverage ; extra == 'dev' - - flake8 ; extra == 'dev' - - wheel ; extra == 'dev' - - zest-releaser[recommended] ; extra == 'dev' - - readme-renderer <25.0 ; python_version == '3.4' and extra == 'dev' - - colorama <=0.4.1 ; python_version == '3.4' and extra == 'dev' - - sphinx ; extra == 'doc' - - sphinx-rtd-theme ; extra == 'doc' - requires_python: '>=2.7' -- kind: pypi - name: send2trash - version: 1.8.3 - url: https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl - sha256: 0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9 - requires_dist: - - pyobjc-framework-cocoa ; sys_platform == 'darwin' and extra == 'nativelib' - - pywin32 ; sys_platform == 'win32' and extra == 'nativelib' - - pyobjc-framework-cocoa ; sys_platform == 'darwin' and extra == 'objc' - - pywin32 ; sys_platform == 'win32' and extra == 'win32' - requires_python: '!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7' -- kind: pypi - name: sentry-sdk - version: 2.1.1 - url: https://files.pythonhosted.org/packages/cf/58/cfbed3fdc41891e9d2b45a5dbe706dcaf35429eb1446e30a504bb2ea9ea2/sentry_sdk-2.1.1-py2.py3-none-any.whl - sha256: 99aeb78fb76771513bd3b2829d12613130152620768d00cd3e45ac00cb17950f - requires_dist: - - urllib3 >=1.26.11 - - certifi - - aiohttp >=3.5 ; extra == 'aiohttp' - - anthropic >=0.16 ; extra == 'anthropic' - - arq >=0.23 ; extra == 'arq' - - asyncpg >=0.23 ; extra == 'asyncpg' - - apache-beam >=2.12 ; extra == 'beam' - - bottle >=0.12.13 ; extra == 'bottle' - - celery >=3 ; extra == 'celery' - - celery-redbeat >=2 ; extra == 'celery-redbeat' - - chalice >=1.16.0 ; extra == 'chalice' - - clickhouse-driver >=0.2.0 ; extra == 'clickhouse-driver' - - django >=1.8 ; extra == 'django' - - falcon >=1.4 ; extra == 'falcon' - - fastapi >=0.79.0 ; extra == 'fastapi' - - flask >=0.11 ; extra == 'flask' - - blinker >=1.1 ; extra == 'flask' - - markupsafe ; extra == 'flask' - - grpcio >=1.21.1 ; extra == 'grpcio' - - httpx >=0.16.0 ; extra == 'httpx' - - huey >=2 ; extra == 'huey' - - huggingface-hub >=0.22 ; extra == 'huggingface_hub' - - langchain >=0.0.210 ; extra == 'langchain' - - loguru >=0.5 ; extra == 'loguru' - - openai >=1.0.0 ; extra == 'openai' - - tiktoken >=0.3.0 ; extra == 'openai' - - opentelemetry-distro >=0.35b0 ; extra == 'opentelemetry' - - opentelemetry-distro ~=0.40b0 ; extra == 'opentelemetry-experimental' - - opentelemetry-instrumentation-aiohttp-client ~=0.40b0 ; extra == 'opentelemetry-experimental' - - opentelemetry-instrumentation-django ~=0.40b0 ; extra == 'opentelemetry-experimental' - - opentelemetry-instrumentation-fastapi ~=0.40b0 ; extra == 'opentelemetry-experimental' - - opentelemetry-instrumentation-flask ~=0.40b0 ; extra == 'opentelemetry-experimental' - - opentelemetry-instrumentation-requests ~=0.40b0 ; extra == 'opentelemetry-experimental' - - opentelemetry-instrumentation-sqlite3 ~=0.40b0 ; extra == 'opentelemetry-experimental' - - opentelemetry-instrumentation-urllib ~=0.40b0 ; extra == 'opentelemetry-experimental' - - pure-eval ; extra == 'pure_eval' - - executing ; extra == 'pure_eval' - - asttokens ; extra == 'pure_eval' - - pymongo >=3.1 ; extra == 'pymongo' - - pyspark >=2.4.4 ; extra == 'pyspark' - - quart >=0.16.1 ; extra == 'quart' - - blinker >=1.1 ; extra == 'quart' - - rq >=0.6 ; extra == 'rq' - - sanic >=0.8 ; extra == 'sanic' - - sqlalchemy >=1.2 ; extra == 'sqlalchemy' - - starlette >=0.19.1 ; extra == 'starlette' - - starlite >=1.48 ; extra == 'starlite' - - tornado >=5 ; extra == 'tornado' - requires_python: '>=3.6' -- kind: pypi - name: setproctitle - version: 1.3.3 - url: https://files.pythonhosted.org/packages/79/e7/54b36be02aee8ad573be68f6f46fd62838735c2f007b22df50eb5e13a20d/setproctitle-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: fc74e84fdfa96821580fb5e9c0b0777c1c4779434ce16d3d62a9c4d8c710df39 - requires_dist: - - pytest ; extra == 'test' - requires_python: '>=3.7' -- kind: conda - name: setuptools - version: 69.5.1 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/setuptools-69.5.1-pyhd8ed1ab_0.conda - sha256: 72d143408507043628b32bed089730b6d5f5445eccc44b59911ec9f262e365e7 - md5: 7462280d81f639363e6e63c81276bd9e - depends: - - python >=3.8 - license: MIT - license_family: MIT - purls: - - pkg:pypi/setuptools - size: 501790 - timestamp: 1713094963112 -- kind: pypi - name: shapely - version: 2.0.4 - url: https://files.pythonhosted.org/packages/81/77/e1475695606a8305c9ad5f5132d911abe8ed1655a6f5c817a69bdd2b5324/shapely-2.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: d2b4431f522b277c79c34b65da128029a9955e4481462cbf7ebec23aab61fc58 - requires_dist: - - numpy <3, >=1.14 - - numpydoc ==1.1.* ; extra == 'docs' - - matplotlib ; extra == 'docs' - - sphinx ; extra == 'docs' - - sphinx-book-theme ; extra == 'docs' - - sphinx-remove-toctrees ; extra == 'docs' - - pytest ; extra == 'test' - - pytest-cov ; extra == 'test' - requires_python: '>=3.7' -- kind: pypi - name: shtab - version: 1.7.1 - url: https://files.pythonhosted.org/packages/e2/d1/a1d3189e7873408b9dc396aef0d7926c198b0df2aa3ddb5b539d3e89a70f/shtab-1.7.1-py3-none-any.whl - sha256: 32d3d2ff9022d4c77a62492b6ec875527883891e33c6b479ba4d41a51e259983 - requires_dist: - - pytest >=6 ; extra == 'dev' - - pytest-cov ; extra == 'dev' - - pytest-timeout ; extra == 'dev' - requires_python: '>=3.7' -- kind: pypi - name: simple-websocket - version: 1.0.0 - url: https://files.pythonhosted.org/packages/6d/ea/288a8ac1d9551354488ff60c0ac6a76acc3b6b60f0460ac1944c75e240da/simple_websocket-1.0.0-py3-none-any.whl - sha256: 1d5bf585e415eaa2083e2bcf02a3ecf91f9712e7b3e6b9fa0b461ad04e0837bc - requires_dist: - - wsproto - - sphinx ; extra == 'docs' - requires_python: '>=3.6' -- kind: pypi - name: simplejson - version: 3.19.2 - url: https://files.pythonhosted.org/packages/cb/b6/ed513a0adc3e2c9654864ffb68266dcab5720d5653428d690e7e4fb32a6c/simplejson-3.19.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 18955c1da6fc39d957adfa346f75226246b6569e096ac9e40f67d102278c3bcb - requires_python: '>=2.5,!=3.0.*,!=3.1.*,!=3.2.*' -- kind: pypi - name: six - version: 1.16.0 - url: https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl - sha256: 8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254 - requires_python: '>=2.7,!=3.0.*,!=3.1.*,!=3.2.*' -- kind: pypi - name: smmap - version: 5.0.1 - url: https://files.pythonhosted.org/packages/a7/a5/10f97f73544edcdef54409f1d839f6049a0d79df68adbc1ceb24d1aaca42/smmap-5.0.1-py3-none-any.whl - sha256: e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da - requires_python: '>=3.7' -- kind: conda - name: snappy - version: 1.2.0 - build: hdb0a2a9_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.0-hdb0a2a9_1.conda - sha256: bb87116b8c6198f6979b3d212e9af12e08e12f2bf09970d0f9b4582607648b22 - md5: 843bbb8ace1d64ac50d64639ff38b014 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: BSD-3-Clause - license_family: BSD - size: 42334 - timestamp: 1712591084054 -- kind: pypi - name: sniffio - version: 1.3.1 - url: https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl - sha256: 2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 - requires_python: '>=3.7' -- kind: pypi - name: soupsieve - version: '2.5' - url: https://files.pythonhosted.org/packages/4c/f3/038b302fdfbe3be7da016777069f26ceefe11a681055ea1f7817546508e3/soupsieve-2.5-py3-none-any.whl - sha256: eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7 - requires_python: '>=3.8' -- kind: pypi - name: splines - version: 0.3.0 - url: https://files.pythonhosted.org/packages/cd/a4/518bee82ace2681327e471f8f59e9958760a564775a8f650489da61205d3/splines-0.3.0-py3-none-any.whl - sha256: 8aadb623d8ada3adf47b6317b08f4cc953210f1bc1984c1cb0c298134d0e346d - requires_dist: - - numpy - requires_python: '>=3.7' -- kind: pypi - name: stack-data - version: 0.6.3 - url: https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl - sha256: d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695 - requires_dist: - - executing >=1.2.0 - - asttokens >=2.1.0 - - pure-eval - - pytest ; extra == 'tests' - - typeguard ; extra == 'tests' - - pygments ; extra == 'tests' - - littleutils ; extra == 'tests' - - cython ; extra == 'tests' -- kind: conda - name: suitesparse - version: 5.10.1 - build: h5a4f163_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/suitesparse-5.10.1-h5a4f163_3.conda - sha256: 235c9321cb76896f3304eea87248a74f52d8c088a38b9cbd98a5366e34756b90 - md5: f363554b9084fb9d5e3366fbbc0d18e0 - depends: - - libblas >=3.9.0,<4.0a0 - - libcblas >=3.9.0,<4.0a0 - - libgcc-ng >=12 - - liblapack >=3.9.0,<4.0a0 - - libstdcxx-ng >=12 - - metis >=5.1.0,<5.1.1.0a0 - - mpfr >=4.2.1,<5.0a0 - - tbb >=2021.11.0 - license: LGPL-2.1-or-later AND BSD-3-Clause AND GPL-2.0-or-later AND Apache-2.0 - size: 1457359 - timestamp: 1705676854887 -- kind: pypi - name: svg-path - version: '6.3' - url: https://files.pythonhosted.org/packages/d6/ea/ec6101e1710ac74e88b10312e9b59734885155e47d7dbb1171e4d347a364/svg.path-6.3-py2.py3-none-any.whl - sha256: 4bd4747679b527f8db9868e1623bee9f416540b658285d903885768d8a427e5a - requires_dist: - - pillow ; extra == 'test' - - black ; extra == 'test' - - check-manifest ; extra == 'test' - - flake8 ; extra == 'test' - - pyroma ; extra == 'test' - - pytest ; extra == 'test' - - pytest-cov ; extra == 'test' - - zest-releaser[recommended] ; extra == 'test' - requires_python: '>=3.8' -- kind: conda - name: svt-av1 - version: 2.0.0 - build: h59595ed_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/svt-av1-2.0.0-h59595ed_0.conda - sha256: eee484177184c7876d258917ab3f209396e6fc59e9bf3603a3ebf1ce8b39df80 - md5: 207e01ffa0eb2d2efb83fb6f46365a21 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - license: BSD-2-Clause - license_family: BSD - size: 2633794 - timestamp: 1710374004661 -- kind: conda - name: sympy - version: '1.12' - build: pypyh9d50eac_103 - build_number: 103 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/sympy-1.12-pypyh9d50eac_103.conda - sha256: 0025dd4e6411423903bf478d1b9fbff0cbbbe546f51c9375dfd6729ef2e1a1ac - md5: 2f7d6347d7acf6edf1ac7f2189f44c8f - depends: - - __unix - - gmpy2 >=2.0.8 - - mpmath >=0.19 - - python * *_cpython - - python >=3.8 - license: BSD-3-Clause - license_family: BSD - purls: - - pkg:pypi/sympy - size: 4256289 - timestamp: 1684180689319 -- kind: conda - name: tbb - version: 2021.12.0 - build: h00ab1b0_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/tbb-2021.12.0-h00ab1b0_0.conda - sha256: 0b48f402e18f293e3c7a4c4e391ed2523f173bdec86aa42658db787196eb27ca - md5: f1b776cff1b426e7e7461a8502a3b731 - depends: - - libgcc-ng >=12 - - libhwloc >=2.10.0,<2.10.1.0a0 - - libstdcxx-ng >=12 - license: Apache-2.0 - license_family: APACHE - size: 194192 - timestamp: 1712959702573 -- kind: pypi - name: tenacity - version: 8.3.0 - url: https://files.pythonhosted.org/packages/61/a1/6bb0cbebefb23641f068bb58a2bc56da9beb2b1c550242e3c540b37698f3/tenacity-8.3.0-py3-none-any.whl - sha256: 3649f6443dbc0d9b01b9d8020a9c4ec7a1ff5f6f3c6c8a036ef371f573fe9185 - requires_dist: - - reno ; extra == 'doc' - - sphinx ; extra == 'doc' - - pytest ; extra == 'test' - - tornado >=4.5 ; extra == 'test' - - typeguard ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: tensorboard - version: 2.16.2 - url: https://files.pythonhosted.org/packages/3a/d0/b97889ffa769e2d1fdebb632084d5e8b53fc299d43a537acee7ec0c021a3/tensorboard-2.16.2-py3-none-any.whl - sha256: 9f2b4e7dad86667615c0e5cd072f1ea8403fc032a299f0072d6f74855775cc45 - requires_dist: - - absl-py >=0.4 - - grpcio >=1.48.2 - - markdown >=2.6.8 - - numpy >=1.12.0 - - protobuf !=4.24.0, >=3.19.6 - - setuptools >=41.0.0 - - six >1.9 - - tensorboard-data-server <0.8.0, >=0.7.0 - - werkzeug >=1.0.1 - requires_python: '>=3.9' -- kind: pypi - name: tensorboard-data-server - version: 0.7.2 - url: https://files.pythonhosted.org/packages/7a/13/e503968fefabd4c6b2650af21e110aa8466fe21432cd7c43a84577a89438/tensorboard_data_server-0.7.2-py3-none-any.whl - sha256: 7e0610d205889588983836ec05dc098e80f97b7e7bbff7e994ebb78f578d0ddb - requires_python: '>=3.7' -- kind: pypi - name: termcolor - version: 2.4.0 - url: https://files.pythonhosted.org/packages/d9/5f/8c716e47b3a50cbd7c146f45881e11d9414def768b7cd9c5e6650ec2a80a/termcolor-2.4.0-py3-none-any.whl - sha256: 9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63 - requires_dist: - - pytest ; extra == 'tests' - - pytest-cov ; extra == 'tests' - requires_python: '>=3.8' -- kind: pypi - name: terminado - version: 0.18.1 - url: https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl - sha256: a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0 - requires_dist: - - ptyprocess ; os_name != 'nt' - - pywinpty >=1.1.0 ; os_name == 'nt' - - tornado >=6.1.0 - - myst-parser ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinx ; extra == 'docs' - - pre-commit ; extra == 'test' - - pytest-timeout ; extra == 'test' - - pytest >=7.0 ; extra == 'test' - - mypy ~=1.6 ; extra == 'typing' - - traitlets >=5.11.1 ; extra == 'typing' - requires_python: '>=3.8' -- kind: pypi - name: threadpoolctl - version: 3.5.0 - url: https://files.pythonhosted.org/packages/4b/2c/ffbf7a134b9ab11a67b0cf0726453cedd9c5043a4fe7a35d1cefa9a1bcfb/threadpoolctl-3.5.0-py3-none-any.whl - sha256: 56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467 - requires_python: '>=3.8' -- kind: pypi - name: tifffile - version: 2024.5.3 - url: https://files.pythonhosted.org/packages/c1/cf/dd1cdf85db58c811816377afd6ba8a240f4611e16f4085201598fb2d5578/tifffile-2024.5.3-py3-none-any.whl - sha256: cac4d939156ff7f16d65fd689637808a7b5b3ad58f9c73327fc009b0aa32c7d5 - requires_dist: - - numpy - - imagecodecs >=2023.8.12 ; extra == 'all' - - matplotlib ; extra == 'all' - - defusedxml ; extra == 'all' - - lxml ; extra == 'all' - - zarr ; extra == 'all' - - fsspec ; extra == 'all' - requires_python: '>=3.9' -- kind: pypi - name: timm - version: 0.6.7 - url: https://files.pythonhosted.org/packages/72/ed/358a8bc5685c31c0fe7765351b202cf6a8c087893b5d2d64f63c950f8beb/timm-0.6.7-py3-none-any.whl - sha256: 4bbd7a5c9ae462ec7fec3d99ffc62ac2012010d755248e3de778d50bce5f6186 - requires_dist: - - torch >=1.4 - - torchvision - requires_python: '>=3.6' -- kind: pypi - name: tinycss2 - version: 1.3.0 - url: https://files.pythonhosted.org/packages/2c/4d/0db5b8a613d2a59bbc29bc5bb44a2f8070eb9ceab11c50d477502a8a0092/tinycss2-1.3.0-py3-none-any.whl - sha256: 54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7 - requires_dist: - - webencodings >=0.4 - - sphinx ; extra == 'doc' - - sphinx-rtd-theme ; extra == 'doc' - - pytest ; extra == 'test' - - ruff ; extra == 'test' - requires_python: '>=3.8' -- kind: conda - name: tk - version: 8.6.13 - build: noxft_h4845f30_101 - build_number: 101 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h4845f30_101.conda - sha256: e0569c9caa68bf476bead1bed3d79650bb080b532c64a4af7d8ca286c08dea4e - md5: d453b98d9c83e71da0741bb0ff4d76bc - depends: - - libgcc-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: TCL - license_family: BSD - size: 3318875 - timestamp: 1699202167581 -- kind: pypi - name: tomli - version: 2.0.1 - url: https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl - sha256: 939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc - requires_python: '>=3.7' -- kind: pypi - name: torch-fidelity - version: 0.3.0 - url: https://files.pythonhosted.org/packages/9f/2c/e24c7e261eaa00fc911c39a5e30f77efbace480aae2548db9ceaef410945/torch_fidelity-0.3.0-py3-none-any.whl - sha256: d01284825595feb7dc3eae3dc9a0d8ced02be764813a3483f109bc142b52a1d3 - requires_dist: - - numpy - - pillow - - scipy - - torch - - torchvision - - tqdm - requires_python: '>=3.6' -- kind: pypi - name: torchmetrics - version: 1.4.0 - url: https://files.pythonhosted.org/packages/aa/d9/b235d32de0f496492b108db7aea0cda42c58b713e2547a149385f1dfc8e3/torchmetrics-1.4.0-py3-none-any.whl - sha256: 18599929a0fff7d4b840a3f9a7700054121850c378caaf7206f4161c0a5dc93c - requires_dist: - - numpy >1.20.0 - - packaging >17.1 - - torch >=1.10.0 - - lightning-utilities >=0.8.0 - - pretty-errors ==1.2.25 - - typing-extensions ; python_version < '3.9' - - torchaudio >=0.10.0 ; extra == 'all' - - pystoi >=0.3.0 ; extra == 'all' - - pycocotools >2.0.0 ; extra == 'all' - - torchvision >=0.8 ; extra == 'all' - - torch-fidelity <=0.4.0 ; extra == 'all' - - scipy >1.0.0 ; extra == 'all' - - transformers >=4.10.0 ; extra == 'all' - - piq <=0.8.0 ; extra == 'all' - - transformers >4.4.0 ; extra == 'all' - - sentencepiece >=0.2.0 ; extra == 'all' - - tqdm >=4.41.0 ; extra == 'all' - - mecab-python3 >=1.0.6 ; extra == 'all' - - nltk >=3.6 ; extra == 'all' - - ipadic >=1.0.0 ; extra == 'all' - - regex >=2021.9.24 ; extra == 'all' - - types-setuptools ; extra == 'all' - - types-tabulate ; extra == 'all' - - types-protobuf ; extra == 'all' - - mypy ==1.9.0 ; extra == 'all' - - types-emoji ; extra == 'all' - - torch ==2.3.0 ; extra == 'all' - - types-requests ; extra == 'all' - - types-six ; extra == 'all' - - types-pyyaml ; extra == 'all' - - matplotlib >=3.3.0 ; extra == 'all' - - scienceplots >=2.0.0 ; extra == 'all' - - torchaudio >=0.10.0 ; extra == 'audio' - - pystoi >=0.3.0 ; extra == 'audio' - - pycocotools >2.0.0 ; extra == 'detection' - - torchvision >=0.8 ; extra == 'detection' - - torchaudio >=0.10.0 ; extra == 'dev' - - pystoi >=0.3.0 ; extra == 'dev' - - pycocotools >2.0.0 ; extra == 'dev' - - torchvision >=0.8 ; extra == 'dev' - - torch-fidelity <=0.4.0 ; extra == 'dev' - - scipy >1.0.0 ; extra == 'dev' - - transformers >=4.10.0 ; extra == 'dev' - - piq <=0.8.0 ; extra == 'dev' - - transformers >4.4.0 ; extra == 'dev' - - sentencepiece >=0.2.0 ; extra == 'dev' - - tqdm >=4.41.0 ; extra == 'dev' - - mecab-python3 >=1.0.6 ; extra == 'dev' - - nltk >=3.6 ; extra == 'dev' - - ipadic >=1.0.0 ; extra == 'dev' - - regex >=2021.9.24 ; extra == 'dev' - - types-setuptools ; extra == 'dev' - - types-tabulate ; extra == 'dev' - - types-protobuf ; extra == 'dev' - - mypy ==1.9.0 ; extra == 'dev' - - types-emoji ; extra == 'dev' - - torch ==2.3.0 ; extra == 'dev' - - types-requests ; extra == 'dev' - - types-six ; extra == 'dev' - - types-pyyaml ; extra == 'dev' - - matplotlib >=3.3.0 ; extra == 'dev' - - scienceplots >=2.0.0 ; extra == 'dev' - - mir-eval >=0.6 ; extra == 'dev' - - pytorch-msssim ==1.0.0 ; extra == 'dev' - - sewar >=0.4.4 ; extra == 'dev' - - mecab-ko-dic >=1.0.0 ; extra == 'dev' - - huggingface-hub <0.23 ; extra == 'dev' - - statsmodels >0.13.5 ; extra == 'dev' - - dython <=0.7.5 ; extra == 'dev' - - mecab-ko >=1.0.0 ; extra == 'dev' - - pandas >1.0.0 ; extra == 'dev' - - numpy <1.25.0 ; extra == 'dev' - - torch-complex <=0.4.3 ; extra == 'dev' - - scikit-image >=0.19.0 ; extra == 'dev' - - pandas >=1.4.0 ; extra == 'dev' - - netcal >1.0.0 ; extra == 'dev' - - monai ==1.3.0 ; extra == 'dev' - - jiwer >=2.3.0 ; extra == 'dev' - - fairlearn ; extra == 'dev' - - sacrebleu >=2.3.0 ; extra == 'dev' - - fast-bss-eval >=0.1.0 ; extra == 'dev' - - kornia >=0.6.7 ; extra == 'dev' - - bert-score ==0.3.13 ; extra == 'dev' - - faster-coco-eval >=1.3.3 ; extra == 'dev' - - lpips <=0.1.4 ; extra == 'dev' - - rouge-score >0.1.0 ; extra == 'dev' - - torch-fidelity <=0.4.0 ; extra == 'image' - - torchvision >=0.8 ; extra == 'image' - - scipy >1.0.0 ; extra == 'image' - - transformers >=4.10.0 ; extra == 'multimodal' - - piq <=0.8.0 ; extra == 'multimodal' - - transformers >4.4.0 ; extra == 'text' - - sentencepiece >=0.2.0 ; extra == 'text' - - tqdm >=4.41.0 ; extra == 'text' - - mecab-python3 >=1.0.6 ; extra == 'text' - - nltk >=3.6 ; extra == 'text' - - ipadic >=1.0.0 ; extra == 'text' - - regex >=2021.9.24 ; extra == 'text' - - types-setuptools ; extra == 'typing' - - types-tabulate ; extra == 'typing' - - types-protobuf ; extra == 'typing' - - mypy ==1.9.0 ; extra == 'typing' - - types-emoji ; extra == 'typing' - - torch ==2.3.0 ; extra == 'typing' - - types-requests ; extra == 'typing' - - types-six ; extra == 'typing' - - types-pyyaml ; extra == 'typing' - - matplotlib >=3.3.0 ; extra == 'visual' - - scienceplots >=2.0.0 ; extra == 'visual' - requires_python: '>=3.8' -- kind: conda - name: torchtriton - version: 2.2.0 - build: py310 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/pytorch/linux-64/torchtriton-2.2.0-py310.tar.bz2 - sha256: c997f2d7fcd50320261de5e1f85ae8a6c78ec62cf2a9fea59f0c223ea128cef2 - md5: 3a7c18eb8b99b0cd2f7278b88212f2ab - depends: - - filelock - - python >=3.10,<3.11.0a0 - - pytorch - license: MIT - size: 185749974 - timestamp: 1704987377808 -- kind: conda - name: torchvision - version: 0.17.2 - build: py310_cu118 - subdir: linux-64 - url: https://conda.anaconda.org/pytorch/linux-64/torchvision-0.17.2-py310_cu118.tar.bz2 - sha256: 3eb63c81a09a4f46ea00a8555ead2e154e3cf239993c99699e16fffa970210f4 - md5: d164aac4009b9a7f8d6e201b08994851 - depends: - - ffmpeg >=4.2 - - libjpeg-turbo - - libpng - - numpy >=1.11 - - pillow >=5.3.0,!=8.3.* - - python >=3.10,<3.11.0a0 - - pytorch 2.2.2 - - pytorch-cuda 11.8.* - - pytorch-mutex 1.0 cuda - - requests - constrains: - - cpuonly <0 - license: BSD - purls: - - pkg:pypi/torchvision - size: 8555800 - timestamp: 1711423012812 -- kind: pypi - name: tornado - version: '6.4' - url: https://files.pythonhosted.org/packages/9f/12/11d0a757bb67278d3380d41955ae98527d5ad18330b2edbdc8de222b569b/tornado-6.4-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: f0251554cdd50b4b44362f73ad5ba7126fc5b2c2895cc62b14a1c2d7ea32f212 - requires_python: '>=3.8' -- kind: pypi - name: tqdm - version: 4.66.4 - url: https://files.pythonhosted.org/packages/18/eb/fdb7eb9e48b7b02554e1664afd3bd3f117f6b6d6c5881438a0b055554f9b/tqdm-4.66.4-py3-none-any.whl - sha256: b75ca56b413b030bc3f00af51fd2c1a1a5eac6a0c1cca83cbb37a5c52abce644 - requires_dist: - - colorama ; platform_system == 'Windows' - - pytest >=6 ; extra == 'dev' - - pytest-cov ; extra == 'dev' - - pytest-timeout ; extra == 'dev' - - pytest-xdist ; extra == 'dev' - - ipywidgets >=6 ; extra == 'notebook' - - slack-sdk ; extra == 'slack' - - requests ; extra == 'telegram' - requires_python: '>=3.7' -- kind: pypi - name: traitlets - version: 5.14.3 - url: https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl - sha256: b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f - requires_dist: - - myst-parser ; extra == 'docs' - - pydata-sphinx-theme ; extra == 'docs' - - sphinx ; extra == 'docs' - - argcomplete >=3.0.3 ; extra == 'test' - - mypy >=1.7.0 ; extra == 'test' - - pre-commit ; extra == 'test' - - pytest-mock ; extra == 'test' - - pytest-mypy-testing ; extra == 'test' - - pytest <8.2, >=7.0 ; extra == 'test' - requires_python: '>=3.8' -- kind: pypi - name: trimesh - version: 4.3.2 - url: https://files.pythonhosted.org/packages/57/7b/557a411622ff3e144d52bebbf8ad8a28bb18ee55ff68e1eb5ebfce755975/trimesh-4.3.2-py3-none-any.whl - sha256: 7563182a9379485b88a44e87156fe54b41fb6f8f030001b9b6de39abdef05c22 - requires_dist: - - numpy >=1.20 - - trimesh[easy,recommend,test] ; extra == 'all' - - colorlog ; extra == 'easy' - - mapbox-earcut ; extra == 'easy' - - chardet ; extra == 'easy' - - lxml ; extra == 'easy' - - jsonschema ; extra == 'easy' - - networkx ; extra == 'easy' - - svg-path ; extra == 'easy' - - pycollada ; extra == 'easy' - - setuptools ; extra == 'easy' - - shapely ; extra == 'easy' - - xxhash ; extra == 'easy' - - rtree ; extra == 'easy' - - httpx ; extra == 'easy' - - scipy ; extra == 'easy' - - embreex ; extra == 'easy' - - pillow ; extra == 'easy' - - vhacdx ; extra == 'easy' - - xatlas ; extra == 'easy' - - glooey ; extra == 'recommend' - - sympy ; extra == 'recommend' - - meshio ; extra == 'recommend' - - pyglet <2 ; extra == 'recommend' - - psutil ; extra == 'recommend' - - scikit-image ; extra == 'recommend' - - python-fcl ; extra == 'recommend' - - openctm ; extra == 'recommend' - - cascadio ; extra == 'recommend' - - manifold3d >=2.3.0 ; extra == 'recommend' - - pytest-cov ; extra == 'test' - - coveralls ; extra == 'test' - - pyright ; extra == 'test' - - ezdxf ; extra == 'test' - - gmsh >=4.12.1 ; extra == 'test' - - pytest ; extra == 'test' - - pymeshlab ; extra == 'test' - - pyinstrument ; extra == 'test' - - matplotlib ; extra == 'test' - - ruff ; extra == 'test' - - pytest-beartype ; python_version >= '3.10' and extra == 'test' - requires_python: '>=3.7' -- kind: pypi - name: typeguard - version: 2.13.3 - url: https://files.pythonhosted.org/packages/9a/bb/d43e5c75054e53efce310e79d63df0ac3f25e34c926be5dffb7d283fb2a8/typeguard-2.13.3-py3-none-any.whl - sha256: 5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1 - requires_dist: - - sphinx-rtd-theme ; extra == 'doc' - - sphinx-autodoc-typehints >=1.2.0 ; extra == 'doc' - - pytest ; extra == 'test' - - typing-extensions ; extra == 'test' - - mypy ; platform_python_implementation != 'PyPy' and extra == 'test' - requires_python: '>=3.5.3' -- kind: pypi - name: types-python-dateutil - version: 2.9.0.20240316 - url: https://files.pythonhosted.org/packages/c7/1b/af4f4c4f3f7339a4b7eb3c0ab13416db98f8ac09de3399129ee5fdfa282b/types_python_dateutil-2.9.0.20240316-py3-none-any.whl - sha256: 6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b - requires_python: '>=3.8' -- kind: conda - name: typing_extensions - version: 4.11.0 - build: pyha770c72_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.11.0-pyha770c72_0.conda - sha256: a7e8714d14f854058e971a6ed44f18cc37cc685f98ddefb2e6b7899a0cc4d1a2 - md5: 6ef2fc37559256cf682d8b3375e89b80 - depends: - - python >=3.8 - license: PSF-2.0 - license_family: PSF - purls: - - pkg:pypi/typing-extensions - size: 37583 - timestamp: 1712330089194 -- kind: pypi - name: tyro - version: 0.8.3 - url: https://files.pythonhosted.org/packages/8a/f6/0b3dca524fdba07dff7b1a029e5546212440e7d2ebd60fc5fc3f4c5d0fbc/tyro-0.8.3-py3-none-any.whl - sha256: 11c657c974e7f5db1ef0659b86c5823850f148b41cc5adf4a7affc835dd551a6 - requires_dist: - - docstring-parser >=0.14.1 - - typing-extensions >=4.7.0 - - rich >=11.1.0 - - shtab >=1.5.6 - - colorama >=0.4.0 ; platform_system == 'Windows' - - eval-type-backport >=0.1.3 ; python_version < '3.10' - - backports-cached-property >=1.0.2 ; python_version < '3.8' - - pyyaml >=6.0 ; extra == 'dev' - - frozendict >=2.3.4 ; extra == 'dev' - - pytest >=7.1.2 ; extra == 'dev' - - pytest-cov >=3.0.0 ; extra == 'dev' - - omegaconf >=2.2.2 ; extra == 'dev' - - attrs >=21.4.0 ; extra == 'dev' - - torch >=1.10.0 ; extra == 'dev' - - pyright >=1.1.349 ; extra == 'dev' - - ruff >=0.1.13 ; extra == 'dev' - - mypy >=1.4.1 ; extra == 'dev' - - numpy >=1.20.0 ; extra == 'dev' - - pydantic >=2.5.2 ; extra == 'dev' - - coverage[toml] >=6.5.0 ; extra == 'dev' - - eval-type-backport >=0.1.3 ; extra == 'dev' - - flax >=0.6.9 ; python_version >= '3.8' and extra == 'dev' - requires_python: '>=3.7' -- kind: conda - name: tzdata - version: 2024a - build: h0c530f3_0 - subdir: noarch - noarch: generic - url: https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda - sha256: 7b2b69c54ec62a243eb6fba2391b5e443421608c3ae5dbff938ad33ca8db5122 - md5: 161081fc7cec0bfda0d86d7cb595f8d8 - license: LicenseRef-Public-Domain - size: 119815 - timestamp: 1706886945727 -- kind: conda - name: ucx - version: 1.15.0 - build: ha691c75_8 - build_number: 8 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/ucx-1.15.0-ha691c75_8.conda - sha256: 85b40ac6607c9e4e32bcb13e95da41ff48a10f813df0c1e74ff32412e1f7da35 - md5: 3f9bc6137b240642504a6c9b07a10c25 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - rdma-core >=51.0 - constrains: - - cuda-version >=11.2,<12 - license: BSD-3-Clause - license_family: BSD - size: 6842006 - timestamp: 1712025621683 -- kind: pypi - name: uri-template - version: 1.3.0 - url: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - sha256: a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363 - requires_dist: - - types-pyyaml ; extra == 'dev' - - mypy ; extra == 'dev' - - flake8 ; extra == 'dev' - - flake8-annotations ; extra == 'dev' - - flake8-bandit ; extra == 'dev' - - flake8-bugbear ; extra == 'dev' - - flake8-commas ; extra == 'dev' - - flake8-comprehensions ; extra == 'dev' - - flake8-continuation ; extra == 'dev' - - flake8-datetimez ; extra == 'dev' - - flake8-docstrings ; extra == 'dev' - - flake8-import-order ; extra == 'dev' - - flake8-literal ; extra == 'dev' - - flake8-modern-annotations ; extra == 'dev' - - flake8-noqa ; extra == 'dev' - - flake8-pyproject ; extra == 'dev' - - flake8-requirements ; extra == 'dev' - - flake8-typechecking-import ; extra == 'dev' - - flake8-use-fstring ; extra == 'dev' - - pep8-naming ; extra == 'dev' - requires_python: '>=3.7' -- kind: conda - name: urllib3 - version: 2.2.1 - build: pyhd8ed1ab_0 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/urllib3-2.2.1-pyhd8ed1ab_0.conda - sha256: d4009dcc9327684d6409706ce17656afbeae690d8522d3c9bc4df57649a352cd - md5: 08807a87fa7af10754d46f63b368e016 - depends: - - brotli-python >=1.0.9 - - pysocks >=1.5.6,<2.0,!=1.5.7 - - python >=3.7 - license: MIT - license_family: MIT - purls: - - pkg:pypi/urllib3 - size: 94669 - timestamp: 1708239595549 -- kind: pypi - name: vhacdx - version: 0.0.6 - url: https://files.pythonhosted.org/packages/7e/af/d3af73e45f8f2d1f3134df23f3832f2b248efadbc4a75d2de2fced454a20/vhacdx-0.0.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: e2c992c36a0149fba8c3581ec7cb6711e9803c48357cea75b08c97c688dece21 - requires_dist: - - numpy - - pytest ; extra == 'test' - requires_python: '>=3.7' -- kind: pypi - name: viser - version: 0.1.27 - url: https://files.pythonhosted.org/packages/e4/3a/c25edb89550c45e3456be6f266eda2850aa0d5226aab012cbfefc3a4decd/viser-0.1.27-py3-none-any.whl - sha256: 55c8c2125bf73100448f43f4a6e2ea0c59bd54371219893e958058797a1743e5 - requires_dist: - - websockets >=10.4 - - numpy >=1.0.0 - - msgpack >=1.0.7 - - imageio >=2.0.0 - - scikit-image >=0.18.0 - - scipy >=1.7.3 - - tqdm >=4.0.0 - - tyro >=0.2.0 - - gdown >=4.6.6 - - rich >=13.3.3 - - trimesh >=3.21.7 - - nodeenv >=1.8.0 - - psutil >=5.9.5 - - yourdfpy >=0.0.53 - - pyliblzfse >=0.4.1 ; platform_system != 'Windows' - - pyright >=1.1.308 ; extra == 'dev' - - mypy >=1.4.1 ; extra == 'dev' - - ruff ==0.3.3 ; extra == 'dev' - - pre-commit ==3.3.2 ; extra == 'dev' - - torch >=1.13.1 ; extra == 'examples' - - matplotlib >=3.7.1 ; extra == 'examples' - requires_python: '>=3.8' -- kind: conda - name: vlfeat - version: 0.9.21 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/vlfeat-0.9.21-hd590300_1.conda - sha256: f3fca24ef6a327072378dd654eba37c6a6da15499ca212eb20b0af422c1ad4c5 - md5: d0749e345cdf00cb4f8f137fd652fefa - depends: - - libgcc-ng >=12 - license: BSD-2-Clause - license_family: BSD - size: 236419 - timestamp: 1684580133228 -- kind: pypi - name: wandb - version: 0.17.0 - url: https://files.pythonhosted.org/packages/b6/49/fd266df341165c7ed94f0e9875bb20cc75a59b1dd9b6f6a51a31db5f8527/wandb-0.17.0-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 56a1dd6e0e635cba3f6ed30b52c71739bdc2a3e57df155619d2d80ee952b4201 - requires_dist: - - click !=8.0.0, >=7.1 - - docker-pycreds >=0.4.0 - - gitpython !=3.1.29, >=1.0.0 - - platformdirs - - protobuf !=4.21.0, <5, >=3.12.0 ; python_version < '3.9' and sys_platform == 'linux' - - protobuf !=4.21.0, <5, >=3.15.0 ; python_version == '3.9' and sys_platform == 'linux' - - protobuf !=4.21.0, <5, >=3.19.0 ; python_version > '3.9' and sys_platform == 'linux' - - protobuf !=4.21.0, <5, >=3.19.0 ; sys_platform != 'linux' - - psutil >=5.0.0 - - pyyaml - - requests <3, >=2.0.0 - - sentry-sdk >=1.0.0 - - setproctitle - - setuptools - - typing-extensions ; python_version < '3.10' - - boto3 ; extra == 'aws' - - azure-identity ; extra == 'azure' - - azure-storage-blob ; extra == 'azure' - - google-cloud-storage ; extra == 'gcp' - - filelock ; extra == 'importers' - - mlflow ; extra == 'importers' - - polars ; extra == 'importers' - - rich ; extra == 'importers' - - tenacity ; extra == 'importers' - - google-cloud-storage ; extra == 'kubeflow' - - kubernetes ; extra == 'kubeflow' - - minio ; extra == 'kubeflow' - - sh ; extra == 'kubeflow' - - awscli ; extra == 'launch' - - azure-containerregistry ; extra == 'launch' - - azure-identity ; extra == 'launch' - - azure-storage-blob ; extra == 'launch' - - boto3 ; extra == 'launch' - - botocore ; extra == 'launch' - - chardet ; extra == 'launch' - - google-auth ; extra == 'launch' - - google-cloud-aiplatform ; extra == 'launch' - - google-cloud-artifact-registry ; extra == 'launch' - - google-cloud-compute ; extra == 'launch' - - google-cloud-storage ; extra == 'launch' - - iso8601 ; extra == 'launch' - - kubernetes ; extra == 'launch' - - kubernetes-asyncio ; extra == 'launch' - - nbconvert ; extra == 'launch' - - nbformat ; extra == 'launch' - - optuna ; extra == 'launch' - - pydantic ; extra == 'launch' - - pyyaml >=6.0.0 ; extra == 'launch' - - tomli ; extra == 'launch' - - typing-extensions ; extra == 'launch' - - bokeh ; extra == 'media' - - moviepy ; extra == 'media' - - numpy ; extra == 'media' - - pillow ; extra == 'media' - - plotly >=5.18.0 ; extra == 'media' - - rdkit-pypi ; extra == 'media' - - soundfile ; extra == 'media' - - cloudpickle ; extra == 'models' - - orjson ; extra == 'perf' - - pydantic >=2.0.0 ; extra == 'reports' - - sweeps >=0.2.0 ; extra == 'sweeps' - requires_python: '>=3.7' -- kind: pypi - name: wcwidth - version: 0.2.13 - url: https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl - sha256: 3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 - requires_dist: - - backports-functools-lru-cache >=1.2.1 ; python_version < '3.2' -- kind: pypi - name: webcolors - version: '1.13' - url: https://files.pythonhosted.org/packages/d5/e1/3e9013159b4cbb71df9bd7611cbf90dc2c621c8aeeb677fc41dad72f2261/webcolors-1.13-py3-none-any.whl - sha256: 29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf - requires_dist: - - furo ; extra == 'docs' - - sphinx ; extra == 'docs' - - sphinx-copybutton ; extra == 'docs' - - sphinx-inline-tabs ; extra == 'docs' - - sphinx-notfound-page ; extra == 'docs' - - sphinxext-opengraph ; extra == 'docs' - - pytest ; extra == 'tests' - - pytest-cov ; extra == 'tests' - requires_python: '>=3.7' -- kind: pypi - name: webencodings - version: 0.5.1 - url: https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl - sha256: a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 -- kind: pypi - name: websocket-client - version: 1.3.3 - url: https://files.pythonhosted.org/packages/67/b4/91683d7d5f66393e8877492fe4763304f82dbe308658a8db98f7a9e20baf/websocket_client-1.3.3-py3-none-any.whl - sha256: 5d55652dc1d0b3c734f044337d929aaf83f4f9138816ec680c1aefefb4dc4877 - requires_dist: - - sphinx >=3.4 ; extra == 'docs' - - sphinx-rtd-theme >=0.5 ; extra == 'docs' - - python-socks ; extra == 'optional' - - wsaccel ; extra == 'optional' - - websockets ; extra == 'test' - requires_python: '>=3.7' -- kind: pypi - name: websockets - version: '12.0' - url: https://files.pythonhosted.org/packages/9a/12/c7a7504f5bf74d6ee0533f6fc7d30d8f4b79420ab179d1df2484b07602eb/websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480 - requires_python: '>=3.8' -- kind: pypi - name: werkzeug - version: 3.0.3 - url: https://files.pythonhosted.org/packages/9d/6e/e792999e816d19d7fcbfa94c730936750036d65656a76a5a688b57a656c4/werkzeug-3.0.3-py3-none-any.whl - sha256: fc9645dc43e03e4d630d23143a04a7f947a9a3b5727cd535fdfe155a17cc48c8 - requires_dist: - - markupsafe >=2.1.1 - - watchdog >=2.3 ; extra == 'watchdog' - requires_python: '>=3.8' -- kind: conda - name: wheel - version: 0.43.0 - build: pyhd8ed1ab_1 - build_number: 1 - subdir: noarch - noarch: python - url: https://conda.anaconda.org/conda-forge/noarch/wheel-0.43.0-pyhd8ed1ab_1.conda - sha256: cb318f066afd6fd64619f14c030569faf3f53e6f50abf743b4c865e7d95b96bc - md5: 0b5293a157c2b5cd513dd1b03d8d3aae - depends: - - python >=3.8 - license: MIT - license_family: MIT - purls: - - pkg:pypi/wheel - size: 57963 - timestamp: 1711546009410 -- kind: pypi - name: widgetsnbextension - version: 4.0.10 - url: https://files.pythonhosted.org/packages/99/bc/82a8c3985209ca7c0a61b383c80e015fd92e74f8ba0ec1af98f9d6ca8dce/widgetsnbextension-4.0.10-py3-none-any.whl - sha256: d37c3724ec32d8c48400a435ecfa7d3e259995201fbefa37163124a9fcb393cc - requires_python: '>=3.7' -- kind: pypi - name: wrapt - version: 1.16.0 - url: https://files.pythonhosted.org/packages/49/83/b40bc1ad04a868b5b5bcec86349f06c1ee1ea7afe51dc3e46131e4f39308/wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf - requires_python: '>=3.6' -- kind: pypi - name: wsproto - version: 1.2.0 - url: https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl - sha256: b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736 - requires_dist: - - h11 <1, >=0.9.0 - requires_python: '>=3.7.0' -- kind: pypi - name: wurlitzer - version: 3.1.0 - url: https://files.pythonhosted.org/packages/51/23/33f2ed4247e30770d964e3952bf4cbe13d22846eca940557447e0a4a2125/wurlitzer-3.1.0-py3-none-any.whl - sha256: a20994e53681fea8fb9d16dc05ff5f9f9701f09723d894456a6d6b29cfb3188d - requires_python: '>=3.5' -- kind: conda - name: x264 - version: 1!164.3095 - build: h166bdaf_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/x264-1!164.3095-h166bdaf_2.tar.bz2 - sha256: 175315eb3d6ea1f64a6ce470be00fa2ee59980108f246d3072ab8b977cb048a5 - md5: 6c99772d483f566d59e25037fea2c4b1 - depends: - - libgcc-ng >=12 - license: GPL-2.0-or-later - license_family: GPL - size: 897548 - timestamp: 1660323080555 -- kind: conda - name: x265 - version: '3.5' - build: h924138e_3 - build_number: 3 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/x265-3.5-h924138e_3.tar.bz2 - sha256: 76c7405bcf2af639971150f342550484efac18219c0203c5ee2e38b8956fe2a0 - md5: e7f6ed84d4623d52ee581325c1587a6b - depends: - - libgcc-ng >=10.3.0 - - libstdcxx-ng >=10.3.0 - license: GPL-2.0-or-later - license_family: GPL - size: 3357188 - timestamp: 1646609687141 -- kind: pypi - name: xatlas - version: 0.0.9 - url: https://files.pythonhosted.org/packages/29/ee/086c7cb4f067238e55fd645188232d67afe1ac6adacbea7a8cf2c6346cd8/xatlas-0.0.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 7112a4c90c14a459dfffbffac1319ad3770a50bfb592f03562c8fe564e765ad7 - requires_dist: - - numpy - - trimesh ; extra == 'test' - - pytest ; extra == 'test' - requires_python: '>=3.7' -- kind: conda - name: xcb-util - version: 0.4.0 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-0.4.0-hd590300_1.conda - sha256: 0c91d87f0efdaadd4e56a5f024f8aab20ec30f90aa2ce9e4ebea05fbc20f71ad - md5: 9bfac7ccd94d54fd21a0501296d60424 - depends: - - libgcc-ng >=12 - - libxcb >=1.13 - - libxcb >=1.15,<1.16.0a0 - license: MIT - license_family: MIT - size: 19728 - timestamp: 1684639166048 -- kind: conda - name: xcb-util-image - version: 0.4.0 - build: h8ee46fc_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-image-0.4.0-h8ee46fc_1.conda - sha256: 92ffd68d2801dbc27afe223e04ae7e78ef605fc8575f107113c93c7bafbd15b0 - md5: 9d7bcddf49cbf727730af10e71022c73 - depends: - - libgcc-ng >=12 - - libxcb >=1.15,<1.16.0a0 - - xcb-util >=0.4.0,<0.5.0a0 - license: MIT - license_family: MIT - size: 24474 - timestamp: 1684679894554 -- kind: conda - name: xcb-util-keysyms - version: 0.4.0 - build: h8ee46fc_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-keysyms-0.4.0-h8ee46fc_1.conda - sha256: 8451d92f25d6054a941b962179180728c48c62aab5bf20ac10fef713d5da6a9a - md5: 632413adcd8bc16b515cab87a2932913 - depends: - - libgcc-ng >=12 - - libxcb >=1.15,<1.16.0a0 - license: MIT - license_family: MIT - size: 14186 - timestamp: 1684680497805 -- kind: conda - name: xcb-util-renderutil - version: 0.3.9 - build: hd590300_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-renderutil-0.3.9-hd590300_1.conda - sha256: 6987588e6fff5892056021c2ea52f7a0deefb2c7348e70d24750e2d60dabf009 - md5: e995b155d938b6779da6ace6c6b13816 - depends: - - libgcc-ng >=12 - - libxcb >=1.13 - - libxcb >=1.15,<1.16.0a0 - license: MIT - license_family: MIT - size: 16955 - timestamp: 1684639112393 -- kind: conda - name: xcb-util-wm - version: 0.4.1 - build: h8ee46fc_1 - build_number: 1 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xcb-util-wm-0.4.1-h8ee46fc_1.conda - sha256: 08ba7147c7579249b6efd33397dc1a8c2404278053165aaecd39280fee705724 - md5: 90108a432fb5c6150ccfee3f03388656 - depends: - - libgcc-ng >=12 - - libxcb >=1.15,<1.16.0a0 - license: MIT - license_family: MIT - size: 52114 - timestamp: 1684679248466 -- kind: conda - name: xkeyboard-config - version: '2.41' - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xkeyboard-config-2.41-hd590300_0.conda - sha256: 56955610c0747ea7cb026bb8aa9ef165ff41d616e89894538173b8b7dd2ee49a - md5: 81f740407b45e3f9047b3174fa94eb9e - depends: - - libgcc-ng >=12 - - xorg-libx11 >=1.8.7,<2.0a0 - license: MIT - license_family: MIT - size: 898045 - timestamp: 1707104384997 -- kind: conda - name: xorg-fixesproto - version: '5.0' - build: h7f98852_1002 - build_number: 1002 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-fixesproto-5.0-h7f98852_1002.tar.bz2 - sha256: 5d2af1b40f82128221bace9466565eca87c97726bb80bbfcd03871813f3e1876 - md5: 65ad6e1eb4aed2b0611855aff05e04f6 - depends: - - libgcc-ng >=9.3.0 - - xorg-xextproto - license: MIT - license_family: MIT - size: 9122 - timestamp: 1617479697350 -- kind: conda - name: xorg-kbproto - version: 1.0.7 - build: h7f98852_1002 - build_number: 1002 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-kbproto-1.0.7-h7f98852_1002.tar.bz2 - sha256: e90b0a6a5d41776f11add74aa030f789faf4efd3875c31964d6f9cfa63a10dd1 - md5: 4b230e8381279d76131116660f5a241a - depends: - - libgcc-ng >=9.3.0 - license: MIT - license_family: MIT - size: 27338 - timestamp: 1610027759842 -- kind: conda - name: xorg-libice - version: 1.1.1 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.1-hd590300_0.conda - sha256: 5aa9b3682285bb2bf1a8adc064cb63aff76ef9178769740d855abb42b0d24236 - md5: b462a33c0be1421532f28bfe8f4a7514 - depends: - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 58469 - timestamp: 1685307573114 -- kind: conda - name: xorg-libsm - version: 1.2.4 - build: h7391055_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.4-h7391055_0.conda - sha256: 089ad5f0453c604e18985480218a84b27009e9e6de9a0fa5f4a20b8778ede1f1 - md5: 93ee23f12bc2e684548181256edd2cf6 - depends: - - libgcc-ng >=12 - - libuuid >=2.38.1,<3.0a0 - - xorg-libice >=1.1.1,<2.0a0 - license: MIT - license_family: MIT - size: 27433 - timestamp: 1685453649160 -- kind: conda - name: xorg-libx11 - version: 1.8.9 - build: h8ee46fc_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.9-h8ee46fc_0.conda - sha256: 3e53ba247f1ad68353f18aceba5bf8ce87e3dea930de85d36946844a7658c9fb - md5: 077b6e8ad6a3ddb741fce2496dd01bec - depends: - - libgcc-ng >=12 - - libxcb >=1.15,<1.16.0a0 - - xorg-kbproto - - xorg-xextproto >=7.3.0,<8.0a0 - - xorg-xproto - license: MIT - license_family: MIT - size: 828060 - timestamp: 1712415742569 -- kind: conda - name: xorg-libxau - version: 1.0.11 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.11-hd590300_0.conda - sha256: 309751371d525ce50af7c87811b435c176915239fc9e132b99a25d5e1703f2d4 - md5: 2c80dc38fface310c9bd81b17037fee5 - depends: - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 14468 - timestamp: 1684637984591 -- kind: conda - name: xorg-libxdmcp - version: 1.1.3 - build: h7f98852_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.3-h7f98852_0.tar.bz2 - sha256: 4df7c5ee11b8686d3453e7f3f4aa20ceef441262b49860733066c52cfd0e4a77 - md5: be93aabceefa2fac576e971aef407908 - depends: - - libgcc-ng >=9.3.0 - license: MIT - license_family: MIT - size: 19126 - timestamp: 1610071769228 -- kind: conda - name: xorg-libxext - version: 1.3.4 - build: h0b41bf4_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.4-h0b41bf4_2.conda - sha256: 73e5cfbdff41ef8a844441f884412aa5a585a0f0632ec901da035a03e1fe1249 - md5: 82b6df12252e6f32402b96dacc656fec - depends: - - libgcc-ng >=12 - - xorg-libx11 >=1.7.2,<2.0a0 - - xorg-xextproto - license: MIT - license_family: MIT - size: 50143 - timestamp: 1677036907815 -- kind: conda - name: xorg-libxfixes - version: 5.0.3 - build: h7f98852_1004 - build_number: 1004 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxfixes-5.0.3-h7f98852_1004.tar.bz2 - sha256: 1e426a1abb774ef1dcf741945ed5c42ad12ea2dc7aeed7682d293879c3e1e4c3 - md5: e9a21aa4d5e3e5f1aed71e8cefd46b6a - depends: - - libgcc-ng >=9.3.0 - - xorg-fixesproto - - xorg-libx11 >=1.7.0,<2.0a0 - license: MIT - license_family: MIT - size: 18145 - timestamp: 1617717802636 -- kind: conda - name: xorg-libxrender - version: 0.9.11 - build: hd590300_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.11-hd590300_0.conda - sha256: 26da4d1911473c965c32ce2b4ff7572349719eaacb88a066db8d968a4132c3f7 - md5: ed67c36f215b310412b2af935bf3e530 - depends: - - libgcc-ng >=12 - - xorg-libx11 >=1.8.6,<2.0a0 - - xorg-renderproto - license: MIT - license_family: MIT - size: 37770 - timestamp: 1688300707994 -- kind: conda - name: xorg-renderproto - version: 0.11.1 - build: h7f98852_1002 - build_number: 1002 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-renderproto-0.11.1-h7f98852_1002.tar.bz2 - sha256: 38942930f233d1898594dd9edf4b0c0786f3dbc12065a0c308634c37fd936034 - md5: 06feff3d2634e3097ce2fe681474b534 - depends: - - libgcc-ng >=9.3.0 - license: MIT - license_family: MIT - size: 9621 - timestamp: 1614866326326 -- kind: conda - name: xorg-xextproto - version: 7.3.0 - build: h0b41bf4_1003 - build_number: 1003 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-xextproto-7.3.0-h0b41bf4_1003.conda - sha256: b8dda3b560e8a7830fe23be1c58cc41f407b2e20ae2f3b6901eb5842ba62b743 - md5: bce9f945da8ad2ae9b1d7165a64d0f87 - depends: - - libgcc-ng >=12 - license: MIT - license_family: MIT - size: 30270 - timestamp: 1677036833037 -- kind: conda - name: xorg-xf86vidmodeproto - version: 2.3.1 - build: h7f98852_1002 - build_number: 1002 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-xf86vidmodeproto-2.3.1-h7f98852_1002.tar.bz2 - sha256: 43398aeacad5b8753b7a1c12cb6bca36124e0c842330372635879c350c430791 - md5: 3ceea9668625c18f19530de98b15d5b0 - depends: - - libgcc-ng >=9.3.0 - license: MIT - license_family: MIT - size: 23875 - timestamp: 1620067286978 -- kind: conda - name: xorg-xproto - version: 7.0.31 - build: h7f98852_1007 - build_number: 1007 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xorg-xproto-7.0.31-h7f98852_1007.tar.bz2 - sha256: f197bb742a17c78234c24605ad1fe2d88b1d25f332b75d73e5ba8cf8fbc2a10d - md5: b4a4381d54784606820704f7b5f05a15 - depends: - - libgcc-ng >=9.3.0 - license: MIT - license_family: MIT - size: 74922 - timestamp: 1607291557628 -- kind: pypi - name: xxhash - version: 3.4.1 - url: https://files.pythonhosted.org/packages/80/8a/1dd41557883b6196f8f092011a5c1f72d4d44cf36d7b67d4a5efe3127949/xxhash-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl - sha256: 00f2fdef6b41c9db3d2fc0e7f94cb3db86693e5c45d6de09625caad9a469635b - requires_python: '>=3.7' -- kind: conda - name: xz - version: 5.2.6 - build: h166bdaf_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2 - sha256: 03a6d28ded42af8a347345f82f3eebdd6807a08526d47899a42d62d319609162 - md5: 2161070d867d1b1204ea749c8eec4ef0 - depends: - - libgcc-ng >=12 - license: LGPL-2.1 and GPL-2.0 - size: 418368 - timestamp: 1660346797927 -- kind: conda - name: yaml - version: 0.2.5 - build: h7f98852_2 - build_number: 2 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2 - sha256: a4e34c710eeb26945bdbdaba82d3d74f60a78f54a874ec10d373811a5d217535 - md5: 4cb3ad778ec2d5a7acbdf254eb1c42ae - depends: - - libgcc-ng >=9.4.0 - license: MIT - license_family: MIT - size: 89141 - timestamp: 1641346969816 -- kind: pypi - name: yourdfpy - version: 0.0.56 - url: https://files.pythonhosted.org/packages/a5/a3/b182c56518f208e3b10a979a24dbe7348fc39edf19e6271b6cf5f8988c96/yourdfpy-0.0.56-py3-none-any.whl - sha256: 85063021aafa97e3818c9e708bc67a804678bbd7f8bbd3c4425f243ff58f9499 - requires_dist: - - lxml - - trimesh[easy] >=3.11.2 - - numpy - - six - - importlib-metadata ; python_version < '3.8' - - pyglet <2 ; extra == 'full' - - setuptools ; extra == 'testing' - - pytest ; extra == 'testing' - - pytest-cov ; extra == 'testing' - requires_python: '>=3.7' -- kind: pypi - name: zipp - version: 3.18.1 - url: https://files.pythonhosted.org/packages/c2/0a/ba9d0ee9536d3ef73a3448e931776e658b36f128d344e175bc32b092a8bf/zipp-3.18.1-py3-none-any.whl - sha256: 206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b - requires_dist: - - sphinx >=3.5 ; extra == 'docs' - - jaraco-packaging >=9.3 ; extra == 'docs' - - rst-linker >=1.9 ; extra == 'docs' - - furo ; extra == 'docs' - - sphinx-lint ; extra == 'docs' - - jaraco-tidelift >=1.4 ; extra == 'docs' - - pytest >=6 ; extra == 'testing' - - pytest-checkdocs >=2.4 ; extra == 'testing' - - pytest-cov ; extra == 'testing' - - pytest-enabler >=2.2 ; extra == 'testing' - - pytest-ruff >=0.2.1 ; extra == 'testing' - - jaraco-itertools ; extra == 'testing' - - jaraco-functools ; extra == 'testing' - - more-itertools ; extra == 'testing' - - big-o ; extra == 'testing' - - pytest-ignore-flaky ; extra == 'testing' - - pytest-mypy ; platform_python_implementation != 'PyPy' and extra == 'testing' - requires_python: '>=3.8' -- kind: conda - name: zlib - version: 1.2.13 - build: hd590300_5 - build_number: 5 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/zlib-1.2.13-hd590300_5.conda - sha256: 9887a04d7e7cb14bd2b52fa01858f05a6d7f002c890f618d9fcd864adbfecb1b - md5: 68c34ec6149623be41a1933ab996a209 - depends: - - libgcc-ng >=12 - - libzlib 1.2.13 hd590300_5 - license: Zlib - license_family: Other - size: 92825 - timestamp: 1686575231103 -- kind: conda - name: zstd - version: 1.5.6 - build: ha6fb4c9_0 - subdir: linux-64 - url: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.6-ha6fb4c9_0.conda - sha256: c558b9cc01d9c1444031bd1ce4b9cff86f9085765f17627a6cd85fc623c8a02b - md5: 4d056880988120e29d75bfff282e0f45 - depends: - - libgcc-ng >=12 - - libstdcxx-ng >=12 - - libzlib >=1.2.13,<1.3.0a0 - license: BSD-3-Clause - license_family: BSD - size: 554846 - timestamp: 1714722996770 diff --git a/pixi.toml b/pixi.toml deleted file mode 100644 index 710ebc2189..0000000000 --- a/pixi.toml +++ /dev/null @@ -1,35 +0,0 @@ -[project] -name = "nerfstudio" -description = "All-in-one repository for state-of-the-art NeRFs" -channels = ["nvidia/label/cuda-11.8.0", "nvidia", "conda-forge", "pytorch"] -platforms = ["linux-64"] - -[system-requirements] -libc = { family="glibc", version="2.30" } - -[tasks] -# || operator in pixi allows running a command after only if the command before || fails -tcnn-install = "python -c 'import tinycudann as tcnn' || python -m pip install ninja git+https://github.com/NVlabs/tiny-cuda-nn/#subdirectory=bindings/torch" -make-third_party-dir = {cmd="ls third_party || mkdir third_party"} -clone-hloc = {cmd="ls Hierarchical-Localization || git clone --recursive https://github.com/cvg/Hierarchical-Localization/", cwd = "third_party", depends-on=["make-third_party-dir"] } -hloc-install = {cmd="python -m pip install -e .", cwd = "third_party/Hierarchical-Localization" , depends-on=["clone-hloc"], outputs=["third_party/Hierarchical-Localization/hloc.egg-info/PKG-INFO"]} -post-install = {cmd="pwd", depends-on=["hloc-install", "tcnn-install"]} - -download-dozer-data = {cmd="ls data/nerfstudio/dozer || ns-download-data nerfstudio --capture-name dozer"} -train-example-splat = {cmd="ns-train splatfacto --data data/nerfstudio/dozer/", depends-on=["post-install", "download-dozer-data"]} -train-example-nerf = {cmd="ns-train nerfacto --data data/nerfstudio/dozer/", depends-on=["post-install", "download-dozer-data"]} - - -[dependencies] -python = ">=3.8,<3.11" -pip = ">=24.0,<25" -cuda = {version = "*", channel="nvidia/label/cuda-11.8.0"} -pytorch-cuda = {version = "11.8.*", channel="pytorch"} -pytorch = {version = ">=2.2.0,<2.3", channel="pytorch"} -torchvision = {version = ">=0.17.0,<0.18", channel="pytorch"} -pyarrow = ">=15.0.2,<15.1" -colmap = ">=3.9.1,<3.10" - - -[pypi-dependencies] -nerfstudio = { path = ".", editable = true} diff --git a/portable_env.bat b/portable_env.bat new file mode 100644 index 0000000000..fe4509fbe3 --- /dev/null +++ b/portable_env.bat @@ -0,0 +1,103 @@ +@echo off +setlocal EnableExtensions DisableDelayedExpansion +cd /d "%~dp0" + +set "ROOT_DIR=%CD%" +set "PORTABLE_CONDA_ROOT=%ROOT_DIR%\.conda" +set "CONDA_BAT=%PORTABLE_CONDA_ROOT%\condabin\conda.bat" +set "CONDA_EXE=%PORTABLE_CONDA_ROOT%\Scripts\conda.exe" +set "BOOTSTRAP_EXE=%ROOT_DIR%\Miniconda3-py310_26.1.1-1-Windows-x86_64.exe" +set "BOOTSTRAP_URL=https://repo.anaconda.com/miniconda/Miniconda3-py310_26.1.1-1-Windows-x86_64.exe" + +if exist "%CONDA_BAT%" goto :activate_portable + +echo [INFO] Portable conda not found. Bootstrapping... + +if not exist "%BOOTSTRAP_EXE%" ( + echo [INFO] Downloading Miniconda Python 3.10 bootstrapper... + powershell -NoProfile -ExecutionPolicy Bypass -Command ^ + "$ProgressPreference='SilentlyContinue';" ^ + "$url='%BOOTSTRAP_URL%';" ^ + "$out='%BOOTSTRAP_EXE%';" ^ + "Invoke-WebRequest -Uri $url -OutFile $out" + if errorlevel 1 ( + echo [ERROR] Failed to download Miniconda bootstrapper. + exit /b 1 + ) +) + +echo [INFO] Installing portable Miniconda into: +echo %PORTABLE_CONDA_ROOT% + +start /wait "" "%BOOTSTRAP_EXE%" ^ + /InstallationType=JustMe ^ + /RegisterPython=0 ^ + /AddToPath=0 ^ + /S ^ + /D=%PORTABLE_CONDA_ROOT% + +if errorlevel 1 ( + echo [ERROR] Portable Miniconda installation failed. + exit /b 1 +) + +if not exist "%CONDA_BAT%" ( + echo [ERROR] Portable conda install completed but conda.bat was not found. + exit /b 1 +) + +if not exist "%PORTABLE_CONDA_ROOT%\.condarc" ( + >"%PORTABLE_CONDA_ROOT%\.condarc" echo auto_activate_base: true + >>"%PORTABLE_CONDA_ROOT%\.condarc" echo channels: + >>"%PORTABLE_CONDA_ROOT%\.condarc" echo - defaults + >>"%PORTABLE_CONDA_ROOT%\.condarc" echo solver: libmamba + >>"%PORTABLE_CONDA_ROOT%\.condarc" echo envs_dirs: + >>"%PORTABLE_CONDA_ROOT%\.condarc" echo - %PORTABLE_CONDA_ROOT%\envs + >>"%PORTABLE_CONDA_ROOT%\.condarc" echo pkgs_dirs: + >>"%PORTABLE_CONDA_ROOT%\.condarc" echo - %PORTABLE_CONDA_ROOT%\pkgs +) + +:activate_portable +echo [INFO] Activating portable conda base... + +set "CONDA_SHLVL=" +set "CONDA_PREFIX=" +set "CONDA_DEFAULT_ENV=" +set "CONDA_EXE=" +set "PYTHONHOME=" +set "PYTHONPATH=" + +call "%CONDA_BAT%" activate "%PORTABLE_CONDA_ROOT%" +if errorlevel 1 ( + echo [ERROR] Failed to activate portable conda base. + exit /b 1 +) + +for /f "delims=" %%P in ('where python 2^>nul') do ( + set "FIRST_PY=%%P" + goto :gotpy +) + +echo [ERROR] python not found after portable activation. +exit /b 1 + +:gotpy +if /I not "%FIRST_PY%"=="%PORTABLE_CONDA_ROOT%\python.exe" ( + echo [WARN] First python on PATH is not portable python: + echo %FIRST_PY% + echo [INFO] Forcing portable python to the front of PATH... + set "PATH=%PORTABLE_CONDA_ROOT%;%PORTABLE_CONDA_ROOT%\Scripts;%PORTABLE_CONDA_ROOT%\Library\bin;%PORTABLE_CONDA_ROOT%\condabin;%PATH%" +) + +echo [OK] Portable conda active. +where python +python --version + +endlocal & ( + set "ROOT_DIR=%ROOT_DIR%" + set "PORTABLE_CONDA_ROOT=%PORTABLE_CONDA_ROOT%" + set "CONDA_BAT=%CONDA_BAT%" + set "CONDA_EXE=%CONDA_EXE%" + set "BOOTSTRAP_EXE=%BOOTSTRAP_EXE%" +) +exit /b 0 diff --git a/pyproject.toml b/pyproject.toml index 585eee4f9c..0a842e06cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,6 +126,7 @@ docs = [ [project.scripts] # Note, add entrypoint name to nerfstudio/scripts/completions/install.py to include CLI completion +ns-install = "ns_installer.cli:main" ns-install-cli = "nerfstudio.scripts.completions.install:entrypoint" ns-process-data = "nerfstudio.scripts.process_data:entrypoint" ns-download-data = "nerfstudio.scripts.downloads.download_data:entrypoint" @@ -138,7 +139,7 @@ ns-dev-test = "nerfstudio.scripts.github.run_actions:entrypoint" ns-dev-sync-viser-message-defs = "nerfstudio.scripts.viewer.sync_viser_message_defs:entrypoint" [tool.setuptools.packages.find] -include = ["nerfstudio*"] +include = ["nerfstudio*", "ns_installer*"] [tool.setuptools.package-data] "*" = ["*.cu", "*.json", "py.typed", "setup.bash", "setup.zsh"] @@ -150,17 +151,16 @@ testpaths = [ ] [tool.pyright] -include = ["nerfstudio"] -exclude = ["**/node_modules", +include = ["nerfstudio", "ns_installer"] +exclude = [ + "**/node_modules", "**/__pycache__", ] defineConstant = { DEBUG = true } - reportMissingImports = "warning" reportMissingTypeStubs = false reportPrivateImportUsage = false - -pythonPlatform = "Linux" +typeCheckingMode = "basic" [tool.ruff] line-length = 120 diff --git a/requirements_pip.txt b/requirements_pip.txt index 05ae5e0508..4ad9ab7d08 100644 --- a/requirements_pip.txt +++ b/requirements_pip.txt @@ -9,7 +9,6 @@ arrow==1.3.0 asttokens==3.0.0 async-lru==2.0.5 attrs==25.3.0 -av==14.3.0 babel==2.17.0 beautifulsoup4==4.13.3 bidict==0.23.1 @@ -115,7 +114,6 @@ narwhals==1.34.1 nbclient==0.10.2 nbconvert==7.16.6 nbformat==5.10.4 -nerfstudio==1.1.5 nest-asyncio==1.6.0 networkx==3.4.2 ninja==1.11.1.4 @@ -186,6 +184,7 @@ Send2Trash==1.8.3 sentencepiece==0.1.99 sentry-sdk==2.25.1 setproctitle==1.3.5 +setuptools==75.1.0 shapely==2.1.0 shtab==1.7.1 simple-websocket==1.1.0 @@ -194,7 +193,7 @@ six==1.17.0 smmap==5.0.2 sniffio==1.3.1 soupsieve==2.6 -splatfacto-w @ git+https://github.com/KevinXu02/splatfacto-w@119a3bfb3aa03669278e174ff11c4dfdcbcf97d7 +splatfacto-w @ git+https://github.com/BlockFrank/splatfacto-w_reforged splines==0.3.0 stack-data==0.6.3 svg.path==6.3 @@ -209,10 +208,8 @@ threadpoolctl==3.6.0 tifffile==2025.3.30 timm==0.6.7 tinycss2==1.4.0 -tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@075158a70b87dba8729188a9cadc9411cfa4b71d#subdirectory=bindings/torch tokenizers==0.13.3 tomli==2.2.1 -pip install git+https://github.com/cvachha/instruct-gs2gs torch==2.1.2+cu118 torch-fidelity==0.3.0 torch_scatter==2.1.2 @@ -232,7 +229,7 @@ tzdata==2025.2 uri-template==1.3.0 urllib3==2.4.0 vhacdx==0.0.8.post2 -viser==0.2.7 +viser wadler_lindig==0.1.4 wandb==0.19.9 wcwidth==0.2.13 @@ -248,6 +245,4 @@ wurlitzer==3.1.1 xatlas==0.0.10 xxhash==3.5.0 yourdfpy==0.0.57 --e git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git@e081caeb81473fac6f057ceb2e560207b4ba5112#egg=zipnerf -pip install torch-scatter -f https://data.pyg.org/whl/torch-2.1.2+${CUDA}.html zipp==3.21.0 diff --git a/requirements_post_zipnerf - Copia.txt b/requirements_post_zipnerf - Copia.txt deleted file mode 100644 index 284b87b139..0000000000 --- a/requirements_post_zipnerf - Copia.txt +++ /dev/null @@ -1,253 +0,0 @@ -absl-py==2.2.2 -accelerate==0.19.0 -annotated-types==0.7.0 -anyio==4.9.0 -appdirs==1.4.4 -argon2-cffi==23.1.0 -argon2-cffi-bindings==21.2.0 -arrow==1.3.0 -asttokens==3.0.0 -async-lru==2.0.5 -attrs==25.3.0 -av==14.3.0 -babel==2.17.0 -beautifulsoup4==4.13.3 -bidict==0.23.1 -bitsandbytes==0.43.0 -bleach==6.2.0 -blinker==1.9.0 -cachetools==5.5.2 -certifi==2025.1.31 -cffi==1.17.1 -charset-normalizer==3.4.1 -click==8.1.8 -colorama==0.4.6 -colorlog==6.9.0 -comet_ml==3.49.7 -comm==0.2.2 -ConfigArgParse==1.7 -configobj==5.0.9 -contourpy==1.3.1 -cryptography==44.0.2 -cuda_backend==0.0.0 -cycler==0.12.1 -dash==3.0.2 -debugpy==1.8.14 -decorator==5.2.1 -defusedxml==0.7.1 -descartes==1.1.0 -diffusers==0.16.1 -dill==0.3.9 -docker-pycreds==0.4.0 -docstring_parser==0.16 -dulwich==0.22.8 -everett==3.1.0 -exceptiongroup==1.2.2 -executing==2.2.0 -fastjsonschema==2.21.1 -filelock==3.18.0 -fire==0.7.0 -Flask==3.0.3 -fonttools==4.57.0 -fpsample==0.3.3 -fqdn==1.5.1 -fsspec==2025.3.2 -gdown==5.2.0 -gin-config==0.5.0 -gitdb==4.0.12 -GitPython==3.1.44 -grpcio==1.71.0 -gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@d23d7ca5dd26c3756967304b621ae88521672ed5 -h11==0.14.0 -h5py==3.13.0 -httpcore==1.0.8 -httpx==0.28.1 -huggingface-hub==0.25.2 -idna==3.10 -imageio==2.37.0 -imageio-ffmpeg==0.6.0 -importlib_metadata==8.6.1 -ipykernel==6.29.5 -ipython==8.35.0 -ipywidgets==8.1.6 -isoduration==20.11.0 -itsdangerous==2.2.0 -jaxtyping==0.3.1 -jedi==0.19.2 -Jinja2==3.1.6 -joblib==1.4.2 -json5==0.12.0 -jsonpointer==3.0.0 -jsonschema==4.23.0 -jsonschema-specifications==2024.10.1 -jupyter==1.1.1 -jupyter-console==6.6.3 -jupyter-events==0.12.0 -jupyter-lsp==2.2.5 -jupyter_client==8.6.3 -jupyter_core==5.7.2 -jupyter_server==2.15.0 -jupyter_server_terminals==0.5.3 -jupyterlab==4.4.0 -jupyterlab_pygments==0.3.0 -jupyterlab_server==2.27.3 -jupyterlab_widgets==3.0.14 -kiwisolver==1.4.8 -lazy_loader==0.4 -lightning-utilities==0.14.3 -lxml==5.3.2 -manifold3d==3.0.1 -mapbox_earcut==1.0.3 -Markdown==3.8 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -matplotlib==3.10.1 -matplotlib-inline==0.1.7 -mdurl==0.1.2 -mediapy==1.2.2 -mistune==3.1.3 -mpmath==1.3.0 -msgpack==1.1.0 -msgpack-numpy==0.4.8 -msgspec==0.19.0 -msvc_runtime==14.42.34433 -multiprocess==0.70.17 -narwhals==1.34.1 -nbclient==0.10.2 -nbconvert==7.16.6 -nbformat==5.10.4 -nerfacc @ git+https://github.com/nerfstudio-project/nerfacc.git@57ccfa14feb94975836ea6913149a86737220f2b -nerfstudio==1.1.5 -nest-asyncio==1.6.0 -networkx==3.4.2 -ninja==1.11.1.4 -nodeenv==1.9.1 -notebook==7.4.0 -notebook_shim==0.2.4 -numpy==1.26.4 -nuscenes-devkit==1.1.9 -open3d==0.19.0 -opencv-contrib-python==4.11.0.86 -opencv-python==4.11.0.86 -opencv-python-headless==4.10.0.84 -overrides==7.7.0 -packaging==24.2 -pandas==2.2.3 -pandocfilters==1.5.1 -parso==0.8.4 -pathos==0.3.3 -pillow==11.1.0 -platformdirs==4.3.7 -plotly==6.0.1 -plyfile==1.1 -pox==0.3.5 -ppft==1.7.6.9 -prometheus_client==0.21.1 -prompt_toolkit==3.0.50 -protobuf==3.20.3 -psutil==7.0.0 -pure_eval==0.2.3 -pycocotools==2.0.8 -pycollada==0.9 -pycparser==2.22 -pydantic==2.11.3 -pydantic_core==2.33.1 -Pygments==2.19.1 -pymeshlab==2023.12.post1 -pyngrok==7.2.3 -pyparsing==3.2.3 -pyquaternion==0.9.9 -PySocks==1.7.1 -python-box==6.1.0 -python-dateutil==2.9.0.post0 -python-engineio==4.11.2 -python-json-logger==3.3.0 -python-socketio==5.12.1 -pytorch-msssim==1.0.0 -pytz==2025.2 -pywin32==310 -pywinpty==2.0.15 -PyYAML==6.0.2 -pyzmq==26.4.0 -rawpy==0.24.0 -referencing==0.36.2 -regex==2024.11.6 -requests==2.32.3 -requests-toolbelt==1.0.0 -retrying==1.3.4 -rfc3339-validator==0.1.4 -rfc3986-validator==0.1.1 -rich==14.0.0 -rpds-py==0.24.0 -rtree==1.4.0 -scikit-image==0.25.2 -scikit-learn==1.6.1 -scipy==1.15.2 -semantic-version==2.10.0 -Send2Trash==1.8.3 -sentencepiece==0.1.99 -sentry-sdk==2.25.1 -setproctitle==1.3.5 -shapely==2.1.0 -shtab==1.7.1 -simple-websocket==1.1.0 -simplejson==3.20.1 -six==1.17.0 -smmap==5.0.2 -sniffio==1.3.1 -soupsieve==2.6 -splatfacto-w @ git+https://github.com/KevinXu02/splatfacto-w@119a3bfb3aa03669278e174ff11c4dfdcbcf97d7 -splines==0.3.0 -stack-data==0.6.3 -svg.path==6.3 -sympy==1.13.3 -tensorboard==2.19.0 -tensorboard-data-server==0.7.2 -tensorboardX==2.6.2.2 -tensorly==0.9.0 -termcolor==3.0.1 -terminado==0.18.1 -threadpoolctl==3.6.0 -tifffile==2025.3.30 -timm==0.6.7 -tinycss2==1.4.0 -tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@075158a70b87dba8729188a9cadc9411cfa4b71d#subdirectory=bindings/torch -tokenizers==0.13.3 -tomli==2.2.1 -torch==2.1.2+cu118 -torch-fidelity==0.3.0 -torch_scatter==2.1.2 -torchmetrics==1.7.1 -torchvision==0.16.2+cu118 -tornado==6.4.2 -tqdm==4.67.1 -traitlets==5.14.3 -transformers==4.29.2 -trimesh==4.6.6 -typeguard==4.4.2 -types-python-dateutil==2.9.0.20241206 -typing-inspection==0.4.0 -typing_extensions==4.13.2 -tyro==0.8.12 -tzdata==2025.2 -uri-template==1.3.0 -urllib3==2.4.0 -vhacdx==0.0.8.post2 -viser==0.2.7 -wadler_lindig==0.1.4 -wandb==0.19.9 -wcwidth==0.2.13 -webcolors==24.11.1 -webencodings==0.5.1 -websocket-client==1.8.0 -websockets==15.0.1 -Werkzeug==3.0.6 -widgetsnbextension==4.0.14 -wrapt==1.17.2 -wsproto==1.2.0 -wurlitzer==3.1.1 -xatlas==0.0.10 -xxhash==3.5.0 -yourdfpy==0.0.57 --e git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git@e081caeb81473fac6f057ceb2e560207b4ba5112#egg=zipnerf -zipp==3.21.0 diff --git a/requirements_post_zipnerf.txt b/requirements_post_zipnerf.txt deleted file mode 100644 index 05ae5e0508..0000000000 --- a/requirements_post_zipnerf.txt +++ /dev/null @@ -1,253 +0,0 @@ -absl-py==2.2.2 -accelerate==0.19.0 -annotated-types==0.7.0 -anyio==4.9.0 -appdirs==1.4.4 -argon2-cffi==23.1.0 -argon2-cffi-bindings==21.2.0 -arrow==1.3.0 -asttokens==3.0.0 -async-lru==2.0.5 -attrs==25.3.0 -av==14.3.0 -babel==2.17.0 -beautifulsoup4==4.13.3 -bidict==0.23.1 -bitsandbytes==0.43.0 -bleach==6.2.0 -blinker==1.9.0 -cachetools==5.5.2 -certifi==2025.1.31 -cffi==1.17.1 -charset-normalizer==3.4.1 -click==8.1.8 -colorama==0.4.6 -colorlog==6.9.0 -comet_ml==3.49.7 -comm==0.2.2 -ConfigArgParse==1.7 -configobj==5.0.9 -contourpy==1.3.1 -cryptography==44.0.2 -cuda_backend==0.0.0 -cycler==0.12.1 -dash==3.0.2 -debugpy==1.8.14 -decorator==5.2.1 -defusedxml==0.7.1 -descartes==1.1.0 -diffusers==0.16.1 -dill==0.3.9 -docker-pycreds==0.4.0 -docstring_parser==0.16 -dulwich==0.22.8 -everett==3.1.0 -exceptiongroup==1.2.2 -executing==2.2.0 -fastjsonschema==2.21.1 -filelock==3.18.0 -fire==0.7.0 -Flask==3.0.3 -fonttools==4.57.0 -fpsample==0.3.3 -fqdn==1.5.1 -fsspec==2025.3.2 -gdown==5.2.0 -gin-config==0.5.0 -gitdb==4.0.12 -GitPython==3.1.44 -grpcio==1.71.0 -h11==0.14.0 -h5py==3.13.0 -httpcore==1.0.8 -httpx==0.28.1 -huggingface-hub==0.25.2 -idna==3.10 -imageio==2.37.0 -imageio-ffmpeg==0.6.0 -importlib_metadata==8.6.1 -ipykernel==6.29.5 -ipython==8.35.0 -ipywidgets==8.1.6 -isoduration==20.11.0 -itsdangerous==2.2.0 -jaxtyping==0.3.1 -jedi==0.19.2 -Jinja2==3.1.6 -joblib==1.4.2 -json5==0.12.0 -jsonpointer==3.0.0 -jsonschema==4.23.0 -jsonschema-specifications==2024.10.1 -jupyter==1.1.1 -jupyter-console==6.6.3 -jupyter-events==0.12.0 -jupyter-lsp==2.2.5 -jupyter_client==8.6.3 -jupyter_core==5.7.2 -jupyter_server==2.15.0 -jupyter_server_terminals==0.5.3 -jupyterlab==4.4.0 -jupyterlab_pygments==0.3.0 -jupyterlab_server==2.27.3 -jupyterlab_widgets==3.0.14 -kiwisolver==1.4.8 -lazy_loader==0.4 -lightning-utilities==0.14.3 -lxml==5.3.2 -manifold3d==3.0.1 -mapbox_earcut==1.0.3 -Markdown==3.8 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -matplotlib==3.10.1 -matplotlib-inline==0.1.7 -mdurl==0.1.2 -mediapy==1.2.2 -mistune==3.1.3 -mpmath==1.3.0 -msgpack==1.1.0 -msgpack-numpy==0.4.8 -msgspec==0.19.0 -msvc_runtime==14.42.34433 -multiprocess==0.70.17 -narwhals==1.34.1 -nbclient==0.10.2 -nbconvert==7.16.6 -nbformat==5.10.4 -nerfstudio==1.1.5 -nest-asyncio==1.6.0 -networkx==3.4.2 -ninja==1.11.1.4 -nodeenv==1.9.1 -notebook==7.4.0 -notebook_shim==0.2.4 -numpy==1.26.4 -nuscenes-devkit==1.1.9 -open3d==0.19.0 -opencv-contrib-python==4.11.0.86 -opencv-python==4.11.0.86 -opencv-python-headless==4.10.0.84 -overrides==7.7.0 -packaging==24.2 -pandas==2.2.3 -pandocfilters==1.5.1 -parso==0.8.4 -pathos==0.3.3 -pillow==11.1.0 -platformdirs==4.3.7 -plotly==6.0.1 -plyfile==1.1 -pox==0.3.5 -ppft==1.7.6.9 -prometheus_client==0.21.1 -prompt_toolkit==3.0.50 -protobuf==3.20.3 -psutil==7.0.0 -pure_eval==0.2.3 -pycocotools==2.0.8 -pycollada==0.9 -pycparser==2.22 -pydantic==2.11.3 -pydantic_core==2.33.1 -Pygments==2.19.1 -pymeshlab==2023.12.post1 -pyngrok==7.2.3 -pyparsing==3.2.3 -pyquaternion==0.9.9 -PySocks==1.7.1 -python-box==6.1.0 -python-dateutil==2.9.0.post0 -python-engineio==4.11.2 -python-json-logger==3.3.0 -python-socketio==5.12.1 -pytorch-msssim==1.0.0 -pytz==2025.2 -pywin32==310 -pywinpty==2.0.15 -PyYAML==6.0.2 -pyzmq==26.4.0 -rawpy==0.24.0 -referencing==0.36.2 -regex==2024.11.6 -requests==2.32.3 -requests-toolbelt==1.0.0 -retrying==1.3.4 -rfc3339-validator==0.1.4 -rfc3986-validator==0.1.1 -rich==14.0.0 -rpds-py==0.24.0 -rtree==1.4.0 -scikit-image==0.25.2 -scikit-learn==1.6.1 -scipy==1.15.2 -semantic-version==2.10.0 -Send2Trash==1.8.3 -sentencepiece==0.1.99 -sentry-sdk==2.25.1 -setproctitle==1.3.5 -shapely==2.1.0 -shtab==1.7.1 -simple-websocket==1.1.0 -simplejson==3.20.1 -six==1.17.0 -smmap==5.0.2 -sniffio==1.3.1 -soupsieve==2.6 -splatfacto-w @ git+https://github.com/KevinXu02/splatfacto-w@119a3bfb3aa03669278e174ff11c4dfdcbcf97d7 -splines==0.3.0 -stack-data==0.6.3 -svg.path==6.3 -sympy==1.13.3 -tensorboard==2.19.0 -tensorboard-data-server==0.7.2 -tensorboardX==2.6.2.2 -tensorly==0.9.0 -termcolor==3.0.1 -terminado==0.18.1 -threadpoolctl==3.6.0 -tifffile==2025.3.30 -timm==0.6.7 -tinycss2==1.4.0 -tinycudann @ git+https://github.com/NVlabs/tiny-cuda-nn/@075158a70b87dba8729188a9cadc9411cfa4b71d#subdirectory=bindings/torch -tokenizers==0.13.3 -tomli==2.2.1 -pip install git+https://github.com/cvachha/instruct-gs2gs -torch==2.1.2+cu118 -torch-fidelity==0.3.0 -torch_scatter==2.1.2 -torchmetrics==1.7.1 -torchvision==0.16.2+cu118 -tornado==6.4.2 -tqdm==4.67.1 -traitlets==5.14.3 -transformers==4.29.2 -trimesh==4.6.6 -typeguard==4.4.2 -types-python-dateutil==2.9.0.20241206 -typing-inspection==0.4.0 -typing_extensions==4.13.2 -tyro==0.8.12 -tzdata==2025.2 -uri-template==1.3.0 -urllib3==2.4.0 -vhacdx==0.0.8.post2 -viser==0.2.7 -wadler_lindig==0.1.4 -wandb==0.19.9 -wcwidth==0.2.13 -webcolors==24.11.1 -webencodings==0.5.1 -websocket-client==1.8.0 -websockets==15.0.1 -Werkzeug==3.0.6 -widgetsnbextension==4.0.14 -wrapt==1.17.2 -wsproto==1.2.0 -wurlitzer==3.1.1 -xatlas==0.0.10 -xxhash==3.5.0 -yourdfpy==0.0.57 --e git+https://github.com/SuLvXiangXin/zipnerf-pytorch.git@e081caeb81473fac6f057ceb2e560207b4ba5112#egg=zipnerf -pip install torch-scatter -f https://data.pyg.org/whl/torch-2.1.2+${CUDA}.html -zipp==3.21.0 diff --git a/run-workflow.bat b/run-workflow.bat new file mode 100644 index 0000000000..e69de29bb2 diff --git a/run_tetranerf.py b/run_tetranerf.py new file mode 100644 index 0000000000..9d3200330b --- /dev/null +++ b/run_tetranerf.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +import os + +# Registra i metodi external prima che Nerfstudio costruisca la CLI. +os.environ["NERFSTUDIO_METHOD_CONFIGS"] = ( + "tetra-nerf=tetranerf.nerfstudio.registration:tetranerf," + "tetra-nerf-original=tetranerf.nerfstudio.registration:tetranerf_original" +) + +# Import esplicito per forzare la registrazione del modulo/plugin. +import tetranerf.nerfstudio.registration # noqa: F401 + +from nerfstudio.scripts.train import entrypoint + + +if __name__ == "__main__": + entrypoint() \ No newline at end of file diff --git a/run_tetranerf_direct.py b/run_tetranerf_direct.py new file mode 100644 index 0000000000..6cfc27c44e --- /dev/null +++ b/run_tetranerf_direct.py @@ -0,0 +1,20 @@ +from __future__ import annotations + +import tyro + +from nerfstudio.scripts.train import main as ns_train_main +from tetranerf.nerfstudio.registration import tetranerf_config + + +def entrypoint(): + # Usa direttamente il vero TrainerConfig di Tetra-NeRF, + # senza passare dal registry/subcommand dummy di ns-train. + config = tyro.cli( + type(tetranerf_config), + default=tetranerf_config, + ) + ns_train_main(config) + + +if __name__ == "__main__": + entrypoint() \ No newline at end of file diff --git a/run_tetranerf_export.py b/run_tetranerf_export.py new file mode 100644 index 0000000000..c3ad56e4a7 --- /dev/null +++ b/run_tetranerf_export.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +import os + +os.environ["NERFSTUDIO_METHOD_CONFIGS"] = ( + "tetra-nerf=tetranerf.nerfstudio.registration:tetranerf," + "tetra-nerf-original=tetranerf.nerfstudio.registration:tetranerf_original" +) + +import tetranerf.nerfstudio.registration # noqa: F401 + +from nerfstudio.scripts.exporter import entrypoint + + +if __name__ == "__main__": + entrypoint() \ No newline at end of file diff --git a/setup.bat b/setup.bat new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test_cli_v2_pinned.bat b/test_cli_v2_pinned.bat new file mode 100644 index 0000000000..4e543893a6 --- /dev/null +++ b/test_cli_v2_pinned.bat @@ -0,0 +1,52 @@ +@echo off +setlocal EnableExtensions DisableDelayedExpansion +cd /d "%~dp0" + +call "%~dp0portable_env.bat" +if errorlevel 1 exit /b %errorlevel% + +set "ROOT_DIR=%CD%" +set "LOCK_DIR=%ROOT_DIR%\deps-lock" + +if not exist "%LOCK_DIR%\pip-freeze-all.txt" ( + echo [ERROR] Missing %LOCK_DIR%\pip-freeze-all.txt + exit /b 1 +) + +echo ============================================ +echo Nerfstudio pinned CLI validation +echo ============================================ +echo. + +python "%ROOT_DIR%\deps_lock.py" --lock-dir "%LOCK_DIR%" --conda-exe "%CONDA_EXE%" check +if errorlevel 1 exit /b %errorlevel% + +python -c "import torch, torchvision, nerfstudio; print('[OK] core imports passed')" +if errorlevel 1 exit /b %errorlevel% + +where ns-install-cli >nul 2>nul +if errorlevel 1 ( + echo [WARN] ns-install-cli not found on PATH in this shell. +) else ( + ns-install-cli --help >nul 2>nul + if errorlevel 1 ( + echo [WARN] ns-install-cli exists but did not return cleanly. + ) else ( + echo [OK] ns-install-cli responded. + ) +) + +where ns-train >nul 2>nul +if errorlevel 1 ( + echo [WARN] ns-train not found on PATH in this shell. +) else ( + ns-train --help >nul 2>nul + if errorlevel 1 ( + echo [WARN] ns-train exists but did not return cleanly. + ) else ( + echo [OK] ns-train responded. + ) +) + +echo [OK] CLI validation complete. +exit /b 0 From f03b67844b718c6e9236b41affd4f231375cd1dc Mon Sep 17 00:00:00 2001 From: Francesco Christopher Date: Sun, 12 Apr 2026 17:56:49 +0200 Subject: [PATCH 8/8] removed Old install notes, use ns-install --help for the new impl features --- INSTALL_NOTES.md | 15 --- README_FULL.md | 253 ----------------------------------------------- 2 files changed, 268 deletions(-) delete mode 100644 INSTALL_NOTES.md delete mode 100644 README_FULL.md diff --git a/INSTALL_NOTES.md b/INSTALL_NOTES.md deleted file mode 100644 index 4775e49710..0000000000 --- a/INSTALL_NOTES.md +++ /dev/null @@ -1,15 +0,0 @@ -# Nerfstudio Custom installer notes - -## What changed -- Removed hardcoded absolute paths for CUDA, Visual Studio, and Conda prefixes. -- Added prompts for new or existing environments instead of forcing a fixed env name. -- Added package flavor selection (`base`, `gen`, `dev`, `dev,docs`). -- Added safer CUDA/Torch presets that follow the Nerfstudio installation guide. -- Split optional methods from the base installer. -- Added a separate helper flow for SDFStudio / Neuralangelo instead of mixing them into the main Nerfstudio env. - -## Why keep SDFStudio / Neuralangelo separate -SDFStudio still documents an older environment target and says it was tested with Python 3.8, Torch 1.12.1 + CUDA 11.3, plus tiny-cuda-nn. It also exposes Neuralangelo support inside the SDFStudio codebase. Mixing that into a modern Nerfstudio 1.1.x environment is likely to create version conflicts. - -## Docker note -Your Docker build likely needs to be split or slimmed down. Right now the Dockerfile builds GLOMAP, COLMAP, tiny-cuda-nn, HLOC, gsplat, and Nerfstudio in one GH Actions job, which is expensive for the default runner budget. diff --git a/README_FULL.md b/README_FULL.md deleted file mode 100644 index ea47df9e22..0000000000 --- a/README_FULL.md +++ /dev/null @@ -1,253 +0,0 @@ -install nerfstudio via base.bat Conda or python venv(experimental) -install extra nerfstudio algorythms via extras_portable_manager.bat -validate the installed and available algorythms with test_cli.py - -NEW: - -Nerfstudio Custom – Installation Prerequisites (Windows) - -Before running the installer, you must install the required toolchains manually. -The installer assumes these are already present and correctly configured. - -1. Install Anaconda (Required) - -Download and install Anaconda (Python distribution) from the official source: - -👉 https://www.anaconda.com/download - -Notes: - -Install for your user (recommended) - -Make sure conda works from terminal: - -conda --version - -Do NOT rely on system Python — the installer will manage environments via Conda - -2. Install CUDA Toolkit 11.8 (Required for GPU) - -Download CUDA 11.8 specifically (do NOT install newer versions for this setup): - -👉 https://developer.nvidia.com/cuda-11-8-0-download-archive - -Important: - -Choose: - -Windows → x86_64 → your OS → exe (local) - -Install with default settings - -After install, verify: - -nvcc --version -Expected path (default): -C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.8 -3. Install Visual Studio Build Tools (Required) - -You need MSVC for compiling native extensions. - -👉 https://visualstudio.microsoft.com/downloads/ - -Install: - -Build Tools for Visual Studio 2022 - -Required components: - -✔ Desktop development with C++ - -✔ MSVC v143 toolset - -✔ Windows 10/11 SDK - -4. Install ROCm HIP SDK (Optional but Recommended) - -Even if you're using NVIDIA, some builds probe for ROCm/HIP. - -Download from official AMD source: - -👉 https://www.amd.com/en/developer/resources/rocm-hub/hip-sdk.html - -Notes: - -Install default configuration - -The installer will disable HIP/ROCm automatically during builds - -This avoids PyTorch extension conflicts on Windows - -5. Environment Variables (Handled by Installer) - -You DO NOT need to manually set: - -CUDA_HOME - -CUDA_PATH - -CUB_HOME - -The installer will: - -detect your paths - -convert them to short (8.3) paths - -override them locally when needed (e.g. for tiny-cuda-nn) - -6. After Prerequisites - -Once everything is installed, run: - -install_windows_all_in_one.bat - -The installer will: - -create or use a Conda environment - -install Nerfstudio + dependencies - -align Torch + CUDA versions - -build native modules (tiny-cuda-nn, gsplat, etc.) - -store built wheels in: - -./wheelhouse -⚠️ Common Pitfalls -Wrong CUDA version - -Must be 11.8 - -Newer versions (12.x) will break builds - -Missing MSVC - -If cl.exe is missing → installs will fail - -Conflicting environment variables - -System-level CUDA_PATH pointing to another version (e.g. 12.8) - -The installer overrides this, but misconfigurations can still leak - -✅ Recommended Setup Summary -Component Version -Python (Conda) 3.10 -CUDA Toolkit 11.8 -PyTorch 2.1.2 + cu118 -Torchvision 0.16.2 -MSVC VS 2022 -# Nerfstudio Custom - -A custom Nerfstudio fork focused on improved Windows installation support and optional extra NeRF methods. - -## Windows prerequisites - -Install these manually before running the installer: - -### 1. Anaconda -Download and install from the official source: -- https://www.anaconda.com/download - -### 2. CUDA Toolkit 11.8 -Use CUDA **11.8** for the recommended Windows stack. -- https://developer.nvidia.com/cuda-11-8-0-download-archive - -### 3. Visual Studio 2022 C++ Build Tools -Install: -- Desktop development with C++ -- MSVC v143 -- Windows 10/11 SDK - -For best compatibility with CUDA 11.8, also install the **14.38** MSVC toolset if available. - -### 4. AMD HIP SDK / ROCm for Windows -Optional, official source: -- https://www.amd.com/en/developer/resources/rocm-hub/hip-sdk.html - -If HIP/ROCm is installed, it may need to be temporarily hidden during some NVIDIA/CUDA extension builds. - ---- - -## Recommended Windows stack - -- Python 3.10 -- Torch 2.1.2 + cu118 -- Torchvision 0.16.2 + cu118 -- CUDA Toolkit 11.8 -- Visual Studio 2022 with MSVC 14.38 preferred - ---- - -## Base install - -Run the Windows all-in-one installer from the repo root. - -It will: -- create or reuse a Python environment -- install Nerfstudio -- align Torch/CUDA versions -- cache wheels in `wheelhouse` -- optionally install extra modules - ---- - -## Important compatibility notes - -### NumPy -Keep an eye on NumPy version drift. - -Some plugins still work best with: -- `numpy<2.0` - -But newer OpenCV wheels may try to force: -- `numpy>=2` - -If plugin installs upgrade NumPy unexpectedly, re-check compatibility before continuing. - -### Torch / CUDA -Do not let plugin-specific requirements replace the stable base stack unless you are intentionally testing a separate environment. - -Recommended stable pair: -- `torch==2.1.2+cu118` -- `torchvision==0.16.2+cu118` - ---- - -## Extra methods and plugin notes - -## Zip-NeRF on Windows - -This plugin is experimental on Windows and needs a few manual fixes. - -### 1. Keep the stable Nerfstudio stack -Use the same stack as the base installer: - -- Python 3.10 -- Torch 2.1.2 + cu118 -- Torchvision 0.16.2 + cu118 -- CUDA Toolkit 11.8 -- MSVC 14.38 / VS2022 C++ tools - -Do not let `zipnerf-pytorch/requirements.txt` replace: -- torch -- torchvision -- numpy -- opencv-python -- opencv-contrib-python - -Those upgrades can break the Nerfstudio environment. - -### 2. Build the CUDA extension without build isolation -The extension imports `torch` during build, so install it with: - -```bat -python -m pip install --no-build-isolation .\extensions\cuda - -## Instruct-GS2GS / IGS2GS on Windows - -If CLI issues appear, pin: -```bat -pip install tyro==0.8.12