From a450ce5edb9e0d70fe7ea5a497b05e7b912656a6 Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 12:57:13 -0400 Subject: [PATCH 01/11] feat: YAML-driven plugin builds with symlink/copy materialization Introduces a build pipeline that turns plugins.d/.yml definitions into installable plugin trees, keeping the canonical ./skills/ catalog as the single source of truth. - plugins.d/_defaults.yml + plugins.d/nvidia-skills.yml: hand-edited plugin spec (curated subset, branding, capabilities) - .github/scripts/build-plugins.{py,sh}: regenerates plugins// (.{claude,codex}-plugin/plugin.json, skills/) and updates both top-level marketplace.json files - .github/workflows/validate-plugins.yml: PR drift guard - plugins/nvidia-skills/: generated catalog plugin tree - .claude-plugin/marketplace.json + .agents/plugins/marketplace.json: top-level marketplaces pointing at the generated subtree The build script supports two materialization strategies via the `materialize_skills:` field: copy - rsync skill content into the plugin tree. Works for Codex and Claude install but duplicates SKILL.md. symlink - relative symlinks back into ./skills/. No duplication and works for Claude + npx skills, but Codex 0.132 silently drops symlinks during `codex plugin add`. nvidia-skills uses `symlink` on this branch to demonstrate the no-duplication design; flip to `copy` in plugins.d/nvidia-skills.yml when shipping for Codex local-marketplace support. Signed-off-by: Jason Dudash --- .agents/plugins/marketplace.json | 20 + .claude-plugin/marketplace.json | 18 + .github/scripts/build-plugins.py | 513 ++++++++++++++++++ .github/scripts/build-plugins.sh | 20 + .github/workflows/validate-plugins.yml | 48 ++ plugins.d/README.md | 68 +++ plugins.d/_defaults.yml | 50 ++ plugins.d/nvidia-skills.yml | 46 ++ .../nvidia-skills/.claude-plugin/plugin.json | 18 + .../nvidia-skills/.codex-plugin/plugin.json | 37 ++ plugins/nvidia-skills/README.md | 7 + plugins/nvidia-skills/assets/nvidia.png | Bin 0 -> 43889 bytes plugins/nvidia-skills/skills/cuopt-install | 1 + .../cuopt-numerical-optimization-api-python | 1 + .../skills/nemoclaw-user-get-started | 1 + 15 files changed, 848 insertions(+) create mode 100644 .agents/plugins/marketplace.json create mode 100644 .claude-plugin/marketplace.json create mode 100755 .github/scripts/build-plugins.py create mode 100755 .github/scripts/build-plugins.sh create mode 100644 .github/workflows/validate-plugins.yml create mode 100644 plugins.d/README.md create mode 100644 plugins.d/_defaults.yml create mode 100644 plugins.d/nvidia-skills.yml create mode 100644 plugins/nvidia-skills/.claude-plugin/plugin.json create mode 100644 plugins/nvidia-skills/.codex-plugin/plugin.json create mode 100644 plugins/nvidia-skills/README.md create mode 100644 plugins/nvidia-skills/assets/nvidia.png create mode 120000 plugins/nvidia-skills/skills/cuopt-install create mode 120000 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python create mode 120000 plugins/nvidia-skills/skills/nemoclaw-user-get-started diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json new file mode 100644 index 00000000..743fb683 --- /dev/null +++ b/.agents/plugins/marketplace.json @@ -0,0 +1,20 @@ +{ + "name": "nvidia-skills", + "interface": { + "displayName": "NVIDIA Skills" + }, + "plugins": [ + { + "name": "nvidia-skills", + "source": { + "source": "local", + "path": "./plugins/nvidia-skills" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Developer Tools" + } + ] +} diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 00000000..5dab0fb3 --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,18 @@ +{ + "name": "nvidia-skills", + "owner": { + "name": "NVIDIA", + "url": "https://github.com/NVIDIA/skills" + }, + "metadata": { + "description": "NVIDIA Skills marketplace — install the curated NVIDIA Skills plugin from this catalog repo.", + "version": "1.0.0" + }, + "plugins": [ + { + "name": "nvidia-skills", + "source": "./plugins/nvidia-skills", + "description": "Build with NVIDIA agent skills." + } + ] +} diff --git a/.github/scripts/build-plugins.py b/.github/scripts/build-plugins.py new file mode 100755 index 00000000..b38fd3ff --- /dev/null +++ b/.github/scripts/build-plugins.py @@ -0,0 +1,513 @@ +#!/usr/bin/env python3 +""" +Build plugin packages from plugins.d/ and per-plugin .skills-manifest.yml files. + +Inputs (hand-maintained): + plugins.d/_defaults.yml + Shared default fields applied to every catalog plugin (author, license, + homepage, brand color, policy URLs, etc.). Per-plugin yaml fields + override these. Filenames starting with `_` are treated as includes and + are never built into a plugin themselves. + + plugins.d/.yml + Catalog plugin spec. Drives full regeneration of plugins// + (skills/ symlinks, .claude-plugin/plugin.json, .codex-plugin/plugin.json) + and its entry in both marketplace.json files. + + plugins//.skills-manifest.yml + Per-plugin skill manifest for hand-curated plugins. Only the skills/ + symlink tree is materialized; plugin.jsons, assets, README, and the + marketplace entry stay hand-edited. + + plugins//assets/ Hand-maintained logo/image assets. + plugins//README.md Optional plugin-specific notes. + +Generated outputs (committed): + plugins//skills// Symlink → ../../../skills// + plugins//.claude-plugin/plugin.json (catalog plugins only) + plugins//.codex-plugin/plugin.json (catalog plugins only) + .claude-plugin/marketplace.json (catalog plugin entries; others preserved) + .agents/plugins/marketplace.json (catalog plugin entries; others preserved) + +The skills/ tree is materialized as RELATIVE symlinks, not file copies. The +canonical SKILL.md lives only under skills///; plugins/ +references it via symlink so the plugin tree stays in sync automatically. + +Usage: + build-plugins.py Build everything. + build-plugins.py --check Build, then fail if the working tree changed + (CI drift guard). + build-plugins.py --only NAME Restrict to a single plugin name. +""" +from __future__ import annotations + +import argparse +import json +import os +import re +import shutil +import subprocess +import sys +from pathlib import Path +from typing import Any + +import yaml + +REPO_ROOT = Path(__file__).resolve().parents[2] +PLUGINS_D = REPO_ROOT / "plugins.d" +PLUGINS_D_DEFAULTS = PLUGINS_D / "_defaults.yml" +PLUGINS_DIR = REPO_ROOT / "plugins" +SKILLS_DIR = REPO_ROOT / "skills" +CLAUDE_MARKETPLACE = REPO_ROOT / ".claude-plugin" / "marketplace.json" +AGENTS_MARKETPLACE = REPO_ROOT / ".agents" / "plugins" / "marketplace.json" + +# Default policy block written for every plugin entry in +# .agents/plugins/marketplace.json. Mirrors the existing convention. +AGENTS_PLUGIN_POLICY = { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL", +} + + +# ---------------------------- helpers ---------------------------------------- + + +def log(msg: str) -> None: + print(msg, flush=True) + + +def die(msg: str, code: int = 1) -> None: + print(f"error: {msg}", file=sys.stderr, flush=True) + sys.exit(code) + + +def read_yaml(path: Path) -> dict[str, Any]: + with path.open() as f: + data = yaml.safe_load(f) + if not isinstance(data, dict): + die(f"{path}: expected a YAML mapping at top level") + return data + + +def read_json(path: Path) -> Any: + with path.open() as f: + return json.load(f) + + +def write_json(path: Path, data: Any) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with path.open("w", encoding="utf-8") as f: + json.dump(data, f, indent=4, ensure_ascii=False) + f.write("\n") + + +def make_relative_symlink(target: Path, link: Path) -> None: + """Create a symlink at `link` pointing at `target`, using a path relative + to `link`'s parent directory so the link survives repo relocation.""" + link.parent.mkdir(parents=True, exist_ok=True) + if link.is_symlink() or link.exists(): + link.unlink() + rel = os.path.relpath(target, link.parent) + os.symlink(rel, link, target_is_directory=True) + + +def expand_skill_paths(entries: list[str]) -> list[tuple[str, Path]]: + """ + Expand each entry into a list of (skill_basename, absolute_source_path). + + - "skills/cuopt/cuopt-install/" → [("cuopt-install", REPO/skills/cuopt/cuopt-install)] + - "skills/cuopt/" → all immediate children of skills/cuopt that contain SKILL.md + """ + out: list[tuple[str, Path]] = [] + for entry in entries: + rel = entry.rstrip("/") + src = (REPO_ROOT / rel).resolve() + if not src.exists(): + die(f"include_skills entry not found: {entry}") + if not src.is_dir(): + die(f"include_skills entry is not a directory: {entry}") + skill_md = src / "SKILL.md" + if skill_md.is_file(): + out.append((src.name, src)) + else: + children = sorted(p for p in src.iterdir() if p.is_dir()) + found = 0 + for child in children: + if (child / "SKILL.md").is_file(): + out.append((child.name, child)) + found += 1 + if found == 0: + die(f"no SKILL.md found under {entry}") + seen: dict[str, Path] = {} + for name, src in out: + if name in seen and seen[name] != src: + die(f"duplicate skill name '{name}': {seen[name]} vs {src}") + seen[name] = src + return out + + +VALID_MATERIALIZATIONS = ("copy", "symlink") + + +def rsync_dir(src: Path, dst: Path) -> None: + """rsync -a --delete src/ dst/ ; src must exist as a directory.""" + if not src.is_dir(): + die(f"source is not a directory: {src}") + dst.mkdir(parents=True, exist_ok=True) + subprocess.run( + ["rsync", "-a", "--delete", f"{src}/", f"{dst}/"], + check=True, + ) + + +def materialize_skills( + plugin_name: str, + entries: list[str], + mode: str = "copy", +) -> list[str]: + """Replace plugins//skills/ with the curated subset. Returns skill names. + + `mode` selects materialization strategy: + - "copy" rsync each skill into plugins//skills//. + Real files. Larger repo. Required for Codex local-install + (codex plugin add silently drops symlinks). + - "symlink" relative symlinks under plugins//skills/ → + ../../../skills//. No duplicate SKILL.md. + Works for Claude install and `npx skills add`. Currently + NOT supported by Codex local marketplace install. + """ + if mode not in VALID_MATERIALIZATIONS: + die( + f"plugin {plugin_name!r}: invalid materialize_skills={mode!r} " + f"(allowed: {', '.join(VALID_MATERIALIZATIONS)})" + ) + plugin_dir = PLUGINS_DIR / plugin_name + target = plugin_dir / "skills" + if target.is_symlink() or target.exists(): + if target.is_symlink(): + target.unlink() + else: + shutil.rmtree(target) + target.mkdir(parents=True) + + pairs = expand_skill_paths(entries) + names: list[str] = [] + for name, src in pairs: + dst = target / name + if mode == "symlink": + make_relative_symlink(src, dst) + else: # copy + rsync_dir(src, dst) + names.append(name) + if mode == "symlink": + word = "symlink" if len(names) == 1 else "symlinks" + else: + word = "copy" if len(names) == 1 else "copies" + log(f" ✓ skills/ ({len(names)} {word})") + return names + + +# ---------------------------- catalog plugin --------------------------------- + + +def render_claude_plugin_json(spec: dict[str, Any]) -> dict[str, Any]: + out: dict[str, Any] = { + "name": spec["name"], + "version": str(spec.get("version", "1.0.0")), + "description": spec["description"], + } + if "display_name" in spec: + out["displayName"] = spec["display_name"] + if "author" in spec: + out["author"] = spec["author"] + if "homepage" in spec: + out["homepage"] = spec["homepage"] + if "repository" in spec: + out["repository"] = spec["repository"] + if "license" in spec: + out["license"] = spec["license"] + if "keywords" in spec: + out["keywords"] = list(spec["keywords"]) + return out + + +def render_codex_plugin_json(spec: dict[str, Any]) -> dict[str, Any]: + out: dict[str, Any] = { + "name": spec["name"], + "version": str(spec.get("version", "1.0.0")), + "description": spec["description"], + } + if "author" in spec: + out["author"] = spec["author"] + if "homepage" in spec: + out["homepage"] = spec["homepage"] + if "repository" in spec: + out["repository"] = spec["repository"] + if "license" in spec: + out["license"] = spec["license"] + if "keywords" in spec: + out["keywords"] = list(spec["keywords"]) + + # Skills tree is always inside the plugin (Codex rejects ".." paths). + out["skills"] = "./skills/" + + interface: dict[str, Any] = {} + if "display_name" in spec: + interface["displayName"] = spec["display_name"] + if "short_description" in spec: + interface["shortDescription"] = spec["short_description"] + if "long_description" in spec: + interface["longDescription"] = spec["long_description"] + if "author" in spec and "name" in spec["author"]: + interface["developerName"] = spec["author"]["name"] + if "category" in spec: + interface["category"] = spec["category"] + if "capabilities" in spec: + interface["capabilities"] = list(spec["capabilities"]) + for src_key, dst_key in ( + ("website_url", "websiteURL"), + ("privacy_policy_url", "privacyPolicyURL"), + ("terms_of_service_url", "termsOfServiceURL"), + ): + value = spec.get(src_key) + if value is None or value == "": + continue + interface[dst_key] = value + if "logo" in spec: + interface["logo"] = spec["logo"] + if "composer_icon" in spec: + interface["composerIcon"] = spec["composer_icon"] + if "screenshots" in spec: + interface["screenshots"] = list(spec["screenshots"]) + if "brand_color" in spec: + interface["brandColor"] = spec["brand_color"] + if "default_prompts" in spec: + interface["defaultPrompt"] = list(spec["default_prompts"]) + if interface: + out["interface"] = interface + return out + + +def build_catalog_plugin(spec: dict[str, Any]) -> str: + name = spec["name"] + if not re.fullmatch(r"[a-z0-9][a-z0-9-]*", name): + die(f"plugin name must be lowercase kebab-case: {name!r}") + plugin_dir = PLUGINS_DIR / name + plugin_dir.mkdir(parents=True, exist_ok=True) + log(f"── catalog plugin: {name} ──") + + mode = spec.get("materialize_skills", "copy") + materialize_skills(name, spec.get("include_skills", []), mode=mode) + + write_json(plugin_dir / ".claude-plugin" / "plugin.json", render_claude_plugin_json(spec)) + log(" ✓ .claude-plugin/plugin.json") + write_json(plugin_dir / ".codex-plugin" / "plugin.json", render_codex_plugin_json(spec)) + log(" ✓ .codex-plugin/plugin.json") + + asset_fields = ["logo", "composer_icon"] + asset_paths: list[str] = [spec[f] for f in asset_fields if isinstance(spec.get(f), str)] + asset_paths += [s for s in (spec.get("screenshots") or []) if isinstance(s, str)] + for asset in asset_paths: + if not asset.startswith("./"): + continue + rel = asset[2:] + path = plugin_dir / rel + if not path.is_file(): + log(f" ! warning: asset declared but missing on disk: {path.relative_to(REPO_ROOT)}") + + return name + + +# ---------------------------- curated plugin --------------------------------- + + +def build_curated_plugin(plugin_dir: Path) -> str: + """ + A curated plugin is one with plugins//.skills-manifest.yml but + no plugins.d/.yml. We materialize only its skills/ tree (as + symlinks) and trust everything else to be hand-maintained. + """ + manifest_path = plugin_dir / ".skills-manifest.yml" + spec = read_yaml(manifest_path) + name = plugin_dir.name + log(f"── curated plugin: {name} ──") + skills = spec.get("skills") or [] + if not skills: + die(f"{manifest_path}: 'skills' list is empty") + mode = spec.get("materialize_skills", "copy") + materialize_skills(name, skills, mode=mode) + return name + + +# ---------------------------- marketplaces ----------------------------------- + + +def is_marketplace_enabled(spec: dict[str, Any], marketplace_key: str) -> bool: + flags = spec.get("marketplace_enabled") or {} + return bool(flags.get(marketplace_key, True)) + + +def upsert_claude_marketplace( + catalog_specs: dict[str, dict[str, Any]], + curated_names: set[str], +) -> None: + if not CLAUDE_MARKETPLACE.is_file(): + die(f"missing {CLAUDE_MARKETPLACE.relative_to(REPO_ROOT)}") + data = read_json(CLAUDE_MARKETPLACE) + existing = data.get("plugins", []) + managed = set(catalog_specs.keys()) + + new_plugins: list[dict[str, Any]] = [] + for entry in existing: + name = entry.get("name") + if name in managed: + continue + if name in curated_names: + new_plugins.append(entry) + for name in sorted(catalog_specs): + spec = catalog_specs[name] + if not is_marketplace_enabled(spec, "claude"): + continue + new_plugins.append({ + "name": name, + "source": f"./plugins/{name}", + "description": spec["description"], + }) + new_plugins.sort(key=lambda p: p.get("name", "")) + data["plugins"] = new_plugins + write_json(CLAUDE_MARKETPLACE, data) + log(f" ✓ {CLAUDE_MARKETPLACE.relative_to(REPO_ROOT)} ({len(new_plugins)} plugin(s))") + + +def upsert_agents_marketplace( + catalog_specs: dict[str, dict[str, Any]], + curated_names: set[str], +) -> None: + if not AGENTS_MARKETPLACE.is_file(): + die(f"missing {AGENTS_MARKETPLACE.relative_to(REPO_ROOT)}") + data = read_json(AGENTS_MARKETPLACE) + existing = data.get("plugins", []) + managed = set(catalog_specs.keys()) + + new_plugins: list[dict[str, Any]] = [] + for entry in existing: + name = entry.get("name") + if name in managed: + continue + if name in curated_names: + new_plugins.append(entry) + for name in sorted(catalog_specs): + spec = catalog_specs[name] + if not is_marketplace_enabled(spec, "codex"): + continue + new_plugins.append({ + "name": name, + "source": {"source": "local", "path": f"./plugins/{name}"}, + "policy": dict(AGENTS_PLUGIN_POLICY), + "category": spec.get("category", "Developer Tools"), + }) + new_plugins.sort(key=lambda p: p.get("name", "")) + data["plugins"] = new_plugins + write_json(AGENTS_MARKETPLACE, data) + log(f" ✓ {AGENTS_MARKETPLACE.relative_to(REPO_ROOT)} ({len(new_plugins)} plugin(s))") + + +# ---------------------------- main ------------------------------------------- + + +def merge_with_defaults(defaults: dict[str, Any], plugin: dict[str, Any]) -> dict[str, Any]: + merged = dict(defaults) + merged.update(plugin) + return merged + + +def discover() -> tuple[dict[str, dict[str, Any]], list[Path]]: + defaults: dict[str, Any] = {} + if PLUGINS_D_DEFAULTS.is_file(): + defaults = read_yaml(PLUGINS_D_DEFAULTS) + + catalog: dict[str, dict[str, Any]] = {} + if PLUGINS_D.is_dir(): + for ymlfile in sorted(PLUGINS_D.glob("*.yml")): + if ymlfile.name.startswith("_"): + continue + plugin_spec = read_yaml(ymlfile) + spec = merge_with_defaults(defaults, plugin_spec) + name = spec.get("name") + if not name: + die(f"{ymlfile}: missing 'name'") + if name in catalog: + die(f"duplicate plugin name '{name}' across plugins.d/") + spec["__source"] = str(ymlfile.relative_to(REPO_ROOT)) + catalog[name] = spec + + curated: list[Path] = [] + if PLUGINS_DIR.is_dir(): + for plugin_dir in sorted(PLUGINS_DIR.iterdir()): + if not plugin_dir.is_dir(): + continue + if plugin_dir.name in catalog: + continue + if (plugin_dir / ".skills-manifest.yml").is_file(): + curated.append(plugin_dir) + return catalog, curated + + +def main(argv: list[str]) -> int: + p = argparse.ArgumentParser(description="Build NVIDIA skills plugins.") + p.add_argument("--only", help="Only build the named plugin.") + p.add_argument( + "--check", + action="store_true", + help="After building, fail if the working tree changed (CI drift guard).", + ) + args = p.parse_args(argv) + + catalog, curated = discover() + if args.only: + catalog = {k: v for k, v in catalog.items() if k == args.only} + curated = [d for d in curated if d.name == args.only] + if not catalog and not curated: + die(f"no plugin named '{args.only}' found in plugins.d/ or plugins/") + + log(f"Found {len(catalog)} catalog plugin(s) and {len(curated)} curated plugin(s).") + + for name in sorted(catalog): + build_catalog_plugin(catalog[name]) + for plugin_dir in curated: + build_curated_plugin(plugin_dir) + + log("── marketplaces ──") + curated_names = {d.name for d in curated} + upsert_claude_marketplace(catalog, curated_names) + upsert_agents_marketplace(catalog, curated_names) + + if args.check: + log("── drift check ──") + result = subprocess.run( + [ + "git", + "status", + "--porcelain", + "plugins/", + ".claude-plugin/marketplace.json", + ".agents/plugins/marketplace.json", + ], + cwd=REPO_ROOT, + capture_output=True, + text=True, + ) + if result.stdout.strip(): + print(result.stdout, file=sys.stderr) + die( + "plugin tree drifted from sources; " + "run .github/scripts/build-plugins.sh and commit the result" + ) + log(" ✓ no drift") + + log("done.") + return 0 + + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) diff --git a/.github/scripts/build-plugins.sh b/.github/scripts/build-plugins.sh new file mode 100755 index 00000000..9952daed --- /dev/null +++ b/.github/scripts/build-plugins.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Wrapper around build-plugins.py that ensures PyYAML is importable. +# Forwards all arguments to the Python script. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +if ! python3 -c "import yaml" 2>/dev/null; then + echo "PyYAML not found; installing for the current user..." >&2 + if pip3 install --user pyyaml >/dev/null 2>&1; then + : + elif pip3 install --user --break-system-packages pyyaml >/dev/null 2>&1; then + : + else + echo "error: failed to install PyYAML; install it manually (pip install pyyaml) and re-run." >&2 + exit 1 + fi +fi + +exec python3 "$SCRIPT_DIR/build-plugins.py" "$@" diff --git a/.github/workflows/validate-plugins.yml b/.github/workflows/validate-plugins.yml new file mode 100644 index 00000000..eecf5f96 --- /dev/null +++ b/.github/workflows/validate-plugins.yml @@ -0,0 +1,48 @@ +# SPDX-License-Identifier: Apache-2.0 +# Copyright (c) 2026 NVIDIA Corporation. All rights reserved. +# +# Validate that the generated plugin tree matches plugins.d/ + skills/. +# +# Runs `build-plugins.sh --check`, which rebuilds into the working tree +# and fails if anything drifts. The cron-driven sync workflow rebuilds +# plugins automatically; this workflow just guards against contributor +# PRs that hand-edit a generated file or forget to re-run the build. + +name: Validate Plugins + +on: + pull_request: + paths: + - "plugins.d/**" + - "skills/**" + - "plugins/**" + - ".claude-plugin/marketplace.json" + - ".agents/plugins/marketplace.json" + - ".github/scripts/build-plugins.*" + - ".github/workflows/validate-plugins.yml" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: validate-plugins-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.x" + + - name: Install PyYAML + run: pip install pyyaml + + - name: Build plugins and fail on drift + run: .github/scripts/build-plugins.sh --check diff --git a/plugins.d/README.md b/plugins.d/README.md new file mode 100644 index 00000000..405ee0f7 --- /dev/null +++ b/plugins.d/README.md @@ -0,0 +1,68 @@ +# `plugins.d/` — plugin catalog source + +Each `.yml` here defines one plugin. The build script +[`.github/scripts/build-plugins.py`](../.github/scripts/build-plugins.py) +parses these files and (re)generates: + +- `plugins//.claude-plugin/plugin.json` +- `plugins//.codex-plugin/plugin.json` +- `plugins//skills//`  **symlinks** into the canonical `skills/` catalog +- `.claude-plugin/marketplace.json` (top-level Claude marketplace registry) +- `.agents/plugins/marketplace.json` (top-level Codex marketplace registry) + +Files whose names start with `_` are treated as includes and are not +themselves built into plugins. `_defaults.yml` provides shared author / +license / capability defaults; per-plugin yaml fields override the defaults +(shallow merge). + +## Source of truth + +The `skills/` directory is the single source of truth — every SKILL.md +exists exactly once there. The plugin tree under `plugins/` is reconstructed +from these YAML files on every build, so adding/removing a curated skill +only requires editing the `include_skills:` list and re-running: + +```sh +.github/scripts/build-plugins.sh +``` + +## `materialize_skills:` — copy vs symlink + +Each plugin selects how `include_skills` are reproduced under +`plugins//skills/`: + +| Mode | What's on disk | Use when | +|---|---|---| +| `copy` (default) | real files (rsync) | publishing to Codex / Anthropic; required for `codex plugin add` (Codex drops symlinks during install) | +| `symlink` | relative symlinks → `../../../skills//` | shipping to Claude only or to `npx skills add` consumers; avoids duplication | + +The default lives in [`_defaults.yml`](./_defaults.yml); override per +plugin by setting `materialize_skills: symlink` (or `copy`) in +`plugins.d/.yml`. + +## Adding a plugin + +1. Create `plugins.d/.yml` with at minimum: + + ```yaml + name: # lowercase kebab-case, must match the file basename + description: ... # one-line summary + display_name: ... + short_description: ... + long_description: ... + category: Developer Tools + include_skills: + - skills/// + ``` + +2. Run `.github/scripts/build-plugins.sh`. +3. Commit the regenerated `plugins//` tree and the updated + `marketplace.json` files alongside the new yaml. + +## Curated (hand-maintained) plugins + +A directory under `plugins//` that has its own +`.skills-manifest.yml` instead of a `plugins.d/.yml` is treated as +a curated plugin: the build script only refreshes its `skills/` symlinks +and otherwise leaves `.claude-plugin/`, `.codex-plugin/`, `assets/`, and +the marketplace entries hand-edited. diff --git a/plugins.d/_defaults.yml b/plugins.d/_defaults.yml new file mode 100644 index 00000000..5a04b36f --- /dev/null +++ b/plugins.d/_defaults.yml @@ -0,0 +1,50 @@ +# Default fields applied to every plugins.d/.yml. +# +# - Anything declared in a per-plugin yaml WINS over the defaults below. +# - Merge is shallow: nested mappings (like `author:`) are replaced wholesale, +# not field-by-field. If you set `author:` in a plugin yaml, supply both +# `name:` and `url:`. +# +# Files starting with `_` are treated as include files by build-plugins.py +# and are NOT themselves built into a plugin. + +version: "1.0.0" + +author: + name: NVIDIA + url: https://github.com/NVIDIA/skills + +homepage: https://github.com/NVIDIA/skills +repository: https://github.com/NVIDIA/skills +license: Apache-2.0 AND CC-BY-4.0 + +# interface.websiteURL is omitted by default — duplicates `homepage` for +# plugins that don't have a distinct product/marketing page. Set it per +# plugin only when there is a real landing page to link to. +# website_url: https://github.com/NVIDIA/skills + +# Privacy policy / Terms of service URLs are only required when a plugin +# actually collects user data or imposes plugin-specific terms. Leave them +# unset by default; uncomment and override per plugin when applicable. +# privacy_policy_url: https://www.nvidia.com/en-us/about-nvidia/privacy-center/ +# terms_of_service_url: https://developer.nvidia.com/legal/terms + +brand_color: "#76b900" + +capabilities: + - Interactive + - Write + +# Marketplace publishing flags default to true. To opt a plugin out of one +# or both self-hosted marketplaces, set marketplace_enabled.{claude,codex}: false +# in that plugin's yaml. + +# How `include_skills` are materialized under plugins//skills/. +# copy - rsync each skill into the plugin tree. Real files. Required +# for Codex local-marketplace install (codex plugin add +# silently drops symlinks). Default. +# symlink - relative symlinks pointing back at the canonical skills/ +# tree. No duplicated SKILL.md. Works for Claude install and +# `npx skills add`; NOT compatible with Codex local install. +# Override per-plugin in plugins.d/.yml when needed. +materialize_skills: copy diff --git a/plugins.d/nvidia-skills.yml b/plugins.d/nvidia-skills.yml new file mode 100644 index 00000000..5fe7c29d --- /dev/null +++ b/plugins.d/nvidia-skills.yml @@ -0,0 +1,46 @@ +name: nvidia-skills + +description: Build with NVIDIA agent skills. + +display_name: NVIDIA +short_description: Provide agentic guidance in your NVIDIA related workflows. +long_description: A curated plugin bundling verified skills to provide guidance in your NVIDIA related workflows. + +category: Developer Tools +logo: ./assets/nvidia.png +composer_icon: ./assets/nvidia.png +# screenshots: [] # optional; supply ./assets/*.png paths when we have any + +keywords: + - nvidia + - agent-skills + - gpu + +default_prompts: + - "Solve an optimization problem with cuOpt." + - "Deploy or debug an NVIDIA RAG Blueprint." + - "Search a video archive with VSS." + +# Curated subset of skills from the canonical ./skills/ catalog. Materialized +# under plugins//skills// via the strategy selected +# by `materialize_skills:` (see below). +include_skills: + - skills/cuopt/cuopt-numerical-optimization-api-python/ + - skills/cuopt/cuopt-install/ + - skills/NemoClaw/nemoclaw-user-get-started/ + +# `symlink` keeps the plugin tree as relative symlinks back into the +# canonical ./skills/ catalog — no duplicated SKILL.md content. Works for +# Claude install and `npx skills add`. Codex 0.132 silently drops symlinks +# during `codex plugin add`; flip this to `copy` if you need Codex +# local-marketplace install to ship real files. +materialize_skills: symlink + +# Inherits from plugins.d/_defaults.yml: +# version, author, homepage, repository, license, +# brand_color, capabilities + +# Published in both self-hosted marketplace.json files (default behaviour). +# marketplace_enabled: +# claude: false +# codex: false diff --git a/plugins/nvidia-skills/.claude-plugin/plugin.json b/plugins/nvidia-skills/.claude-plugin/plugin.json new file mode 100644 index 00000000..3e5f4505 --- /dev/null +++ b/plugins/nvidia-skills/.claude-plugin/plugin.json @@ -0,0 +1,18 @@ +{ + "name": "nvidia-skills", + "version": "1.0.0", + "description": "Build with NVIDIA agent skills.", + "displayName": "NVIDIA", + "author": { + "name": "NVIDIA", + "url": "https://github.com/NVIDIA/skills" + }, + "homepage": "https://github.com/NVIDIA/skills", + "repository": "https://github.com/NVIDIA/skills", + "license": "Apache-2.0 AND CC-BY-4.0", + "keywords": [ + "nvidia", + "agent-skills", + "gpu" + ] +} diff --git a/plugins/nvidia-skills/.codex-plugin/plugin.json b/plugins/nvidia-skills/.codex-plugin/plugin.json new file mode 100644 index 00000000..16a59bde --- /dev/null +++ b/plugins/nvidia-skills/.codex-plugin/plugin.json @@ -0,0 +1,37 @@ +{ + "name": "nvidia-skills", + "version": "1.0.0", + "description": "Build with NVIDIA agent skills.", + "author": { + "name": "NVIDIA", + "url": "https://github.com/NVIDIA/skills" + }, + "homepage": "https://github.com/NVIDIA/skills", + "repository": "https://github.com/NVIDIA/skills", + "license": "Apache-2.0 AND CC-BY-4.0", + "keywords": [ + "nvidia", + "agent-skills", + "gpu" + ], + "skills": "./skills/", + "interface": { + "displayName": "NVIDIA", + "shortDescription": "Provide agentic guidance in your NVIDIA related workflows.", + "longDescription": "A curated plugin bundling verified skills to provide guidance in your NVIDIA related workflows.", + "developerName": "NVIDIA", + "category": "Developer Tools", + "capabilities": [ + "Interactive", + "Write" + ], + "logo": "./assets/nvidia.png", + "composerIcon": "./assets/nvidia.png", + "brandColor": "#76b900", + "defaultPrompt": [ + "Solve an optimization problem with cuOpt.", + "Deploy or debug an NVIDIA RAG Blueprint.", + "Search a video archive with VSS." + ] + } +} diff --git a/plugins/nvidia-skills/README.md b/plugins/nvidia-skills/README.md new file mode 100644 index 00000000..95d5bd7d --- /dev/null +++ b/plugins/nvidia-skills/README.md @@ -0,0 +1,7 @@ +# Official NVIDIA Plugin + +This plugin is **not** part of the `nvidia/skills` self-hosted marketplace. It is curated for delivery to the official OpenAI Bundled and Anthropic Official marketplaces. + +The contents here (skills, plugin manifests) are generated from `plugins.d/nvidia.yml` by `.github/scripts/build-plugins.sh`. The yaml sets `marketplace_enabled.{claude,codex}: false`, which keeps it out of `.claude-plugin/marketplace.json` and `.agents/plugins/marketplace.json` while still producing a self-contained plugin folder ready to ship upstream. + +To change which skills this plugin bundles, edit `plugins.d/nvidia.yml` and re-run the build script. Hand-maintained inside this directory: `assets/` (logo) and this README. diff --git a/plugins/nvidia-skills/assets/nvidia.png b/plugins/nvidia-skills/assets/nvidia.png new file mode 100644 index 0000000000000000000000000000000000000000..e7165f5d1cc877f7badd2c45163d0f00b854f433 GIT binary patch literal 43889 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%0A>)Ik>V4aLiIiP^&?B2qAq_0*|7AZb+Gq>)~1_ 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 W1rg}LaNB^}rLGKlS*m35@&5qdH|OR6 literal 0 HcmV?d00001 diff --git a/plugins/nvidia-skills/skills/cuopt-install b/plugins/nvidia-skills/skills/cuopt-install new file mode 120000 index 00000000..71ef5d4b --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-install @@ -0,0 +1 @@ +../../../skills/cuopt/cuopt-install \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python new file mode 120000 index 00000000..9669719b --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python @@ -0,0 +1 @@ +../../../skills/cuopt/cuopt-numerical-optimization-api-python \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started b/plugins/nvidia-skills/skills/nemoclaw-user-get-started new file mode 120000 index 00000000..6b780fc1 --- /dev/null +++ b/plugins/nvidia-skills/skills/nemoclaw-user-get-started @@ -0,0 +1 @@ +../../../skills/NemoClaw/nemoclaw-user-get-started \ No newline at end of file From 613ce4c32860448e4be5eece84d1957ec957b7c0 Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 13:15:04 -0400 Subject: [PATCH 02/11] fix: emit explicit skills field in generated Claude plugin.json Mirror the Codex side, which already declares "skills": "./skills/". Claude expects an array of paths, so we emit ["./skills/"] (container path; Claude scans immediate children for SKILL.md). Signed-off-by: Jason Dudash --- .github/scripts/build-plugins.py | 4 ++++ plugins/nvidia-skills/.claude-plugin/plugin.json | 3 +++ 2 files changed, 7 insertions(+) diff --git a/.github/scripts/build-plugins.py b/.github/scripts/build-plugins.py index b38fd3ff..edd90278 100755 --- a/.github/scripts/build-plugins.py +++ b/.github/scripts/build-plugins.py @@ -228,6 +228,10 @@ def render_claude_plugin_json(spec: dict[str, Any]) -> dict[str, Any]: out["license"] = spec["license"] if "keywords" in spec: out["keywords"] = list(spec["keywords"]) + # Skills tree is always inside the plugin (Codex rejects ".." paths, + # Anthropic spec requires "./" prefixes). Container path; Claude scans + # immediate children for SKILL.md. + out["skills"] = ["./skills/"] return out diff --git a/plugins/nvidia-skills/.claude-plugin/plugin.json b/plugins/nvidia-skills/.claude-plugin/plugin.json index 3e5f4505..657774ab 100644 --- a/plugins/nvidia-skills/.claude-plugin/plugin.json +++ b/plugins/nvidia-skills/.claude-plugin/plugin.json @@ -14,5 +14,8 @@ "nvidia", "agent-skills", "gpu" + ], + "skills": [ + "./skills/" ] } From 96b4974dbc9f520cae92fa9b5e1956a3c4740ac5 Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 14:56:55 -0400 Subject: [PATCH 03/11] =?UTF-8?q?refactor:=20rename=20materialize=5Fskills?= =?UTF-8?q?=20=E2=86=92=20skill=5Ffiles;=20default=20to=20copy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the per-plugin YAML option that selects how `include_skills` show up under `plugins//skills/` from `materialize_skills` to `skill_files`, with values `copy | symlink`. Both modes remain supported; this branch's purpose is to provide that choice. `copy` stays the default in plugins.d/_defaults.yml — Codex 0.132 silently drops symlinks during `codex plugin add`, so real files are required for local-marketplace install. Plugins that ship to Claude / `npx skills add` only can opt into `symlink` per-plugin to avoid SKILL.md duplication. Touched: - .github/scripts/build-plugins.py: read spec.get("skill_files"), updated error message - plugins.d/_defaults.yml: skill_files: copy - plugins.d/nvidia-skills.yml: comment now points at skill_files (no override; inherits copy) - plugins.d/README.md: heading + override example Also folds in the marketplace identity rename from another branch (`nvidia-skills` → `nvidia-official` in both marketplace.json files) and regenerates plugins/nvidia-skills/skills/ as real directories under the new copy default. Signed-off-by: Jason Dudash --- .agents/plugins/marketplace.json | 4 +- .claude-plugin/marketplace.json | 4 +- .github/scripts/build-plugins.py | 6 +- plugins.d/README.md | 6 +- plugins.d/_defaults.yml | 4 +- plugins.d/nvidia-skills.yml | 16 +- plugins/nvidia-skills/skills/cuopt-install | 1 - .../skills/cuopt-install/SKILL.md | 128 ++ .../skills/cuopt-install/evals/evals.json | 213 ++++ .../resources/verification_examples.md | 172 +++ .../cuopt-numerical-optimization-api-python | 1 - .../SKILL.md | 278 +++++ .../assets/README.md | 17 + .../assets/least_squares/README.md | 5 + .../assets/least_squares/model.py | 24 + .../assets/lp_basic/README.md | 7 + .../assets/lp_basic/model.py | 36 + .../assets/lp_duals/README.md | 7 + .../assets/lp_duals/model.py | 38 + .../assets/lp_warmstart/README.md | 5 + .../assets/lp_warmstart/model.py | 52 + .../assets/maximization_workaround/README.md | 5 + .../assets/maximization_workaround/model.py | 22 + .../assets/milp_basic/README.md | 10 + .../assets/milp_basic/incumbent_callback.py | 50 + .../assets/milp_basic/model.py | 36 + .../assets/milp_production_planning/README.md | 5 + .../assets/milp_production_planning/model.py | 33 + .../assets/mps_solver/README.md | 88 ++ .../assets/mps_solver/data/README.md | 82 ++ .../assets/mps_solver/data/sample.mps | 19 + .../assets/mps_solver/model.py | 283 +++++ .../assets/mps_solver/results.md | 90 ++ .../assets/portfolio/README.md | 7 + .../assets/portfolio/model.py | 49 + .../evals/SOURCES.md | 40 + .../evals/evals.json | 1091 +++++++++++++++++ .../resources/qp_examples.md | 198 +++ .../skills/nemoclaw-user-get-started | 1 - .../skills/nemoclaw-user-get-started/SKILL.md | 353 ++++++ .../references/prerequisites.md | 62 + .../references/quickstart-hermes.md | 170 +++ .../references/windows-preparation.md | 136 ++ 43 files changed, 3828 insertions(+), 26 deletions(-) delete mode 120000 plugins/nvidia-skills/skills/cuopt-install create mode 100644 plugins/nvidia-skills/skills/cuopt-install/SKILL.md create mode 100644 plugins/nvidia-skills/skills/cuopt-install/evals/evals.json create mode 100644 plugins/nvidia-skills/skills/cuopt-install/resources/verification_examples.md delete mode 120000 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/SKILL.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/incumbent_callback.py create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/sample.mps create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/results.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/SOURCES.md create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/evals.json create mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/resources/qp_examples.md delete mode 120000 plugins/nvidia-skills/skills/nemoclaw-user-get-started create mode 100644 plugins/nvidia-skills/skills/nemoclaw-user-get-started/SKILL.md create mode 100644 plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/prerequisites.md create mode 100644 plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/quickstart-hermes.md create mode 100644 plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/windows-preparation.md diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json index 743fb683..dc549b4f 100644 --- a/.agents/plugins/marketplace.json +++ b/.agents/plugins/marketplace.json @@ -1,7 +1,7 @@ { - "name": "nvidia-skills", + "name": "nvidia-official", "interface": { - "displayName": "NVIDIA Skills" + "displayName": "NVIDIA Official" }, "plugins": [ { diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 5dab0fb3..829a6030 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,11 +1,11 @@ { - "name": "nvidia-skills", + "name": "nvidia-official", "owner": { "name": "NVIDIA", "url": "https://github.com/NVIDIA/skills" }, "metadata": { - "description": "NVIDIA Skills marketplace — install the curated NVIDIA Skills plugin from this catalog repo.", + "description": "NVIDIA plugin marketplace — install the curated NVIDIA plugins and skills from this catalog repo.", "version": "1.0.0" }, "plugins": [ diff --git a/.github/scripts/build-plugins.py b/.github/scripts/build-plugins.py index edd90278..8f5f4dbc 100755 --- a/.github/scripts/build-plugins.py +++ b/.github/scripts/build-plugins.py @@ -178,7 +178,7 @@ def materialize_skills( """ if mode not in VALID_MATERIALIZATIONS: die( - f"plugin {plugin_name!r}: invalid materialize_skills={mode!r} " + f"plugin {plugin_name!r}: invalid skill_files={mode!r} " f"(allowed: {', '.join(VALID_MATERIALIZATIONS)})" ) plugin_dir = PLUGINS_DIR / plugin_name @@ -300,7 +300,7 @@ def build_catalog_plugin(spec: dict[str, Any]) -> str: plugin_dir.mkdir(parents=True, exist_ok=True) log(f"── catalog plugin: {name} ──") - mode = spec.get("materialize_skills", "copy") + mode = spec.get("skill_files", "copy") materialize_skills(name, spec.get("include_skills", []), mode=mode) write_json(plugin_dir / ".claude-plugin" / "plugin.json", render_claude_plugin_json(spec)) @@ -338,7 +338,7 @@ def build_curated_plugin(plugin_dir: Path) -> str: skills = spec.get("skills") or [] if not skills: die(f"{manifest_path}: 'skills' list is empty") - mode = spec.get("materialize_skills", "copy") + mode = spec.get("skill_files", "copy") materialize_skills(name, skills, mode=mode) return name diff --git a/plugins.d/README.md b/plugins.d/README.md index 405ee0f7..885a55b5 100644 --- a/plugins.d/README.md +++ b/plugins.d/README.md @@ -26,9 +26,9 @@ only requires editing the `include_skills:` list and re-running: .github/scripts/build-plugins.sh ``` -## `materialize_skills:` — copy vs symlink +## `skill_files:` — copy vs symlink -Each plugin selects how `include_skills` are reproduced under +Each plugin selects what kind of files end up under `plugins//skills/`: | Mode | What's on disk | Use when | @@ -37,7 +37,7 @@ Each plugin selects how `include_skills` are reproduced under | `symlink` | relative symlinks → `../../../skills//` | shipping to Claude only or to `npx skills add` consumers; avoids duplication | The default lives in [`_defaults.yml`](./_defaults.yml); override per -plugin by setting `materialize_skills: symlink` (or `copy`) in +plugin by setting `skill_files: symlink` (or `copy`) in `plugins.d/.yml`. ## Adding a plugin diff --git a/plugins.d/_defaults.yml b/plugins.d/_defaults.yml index 5a04b36f..fc8dc51d 100644 --- a/plugins.d/_defaults.yml +++ b/plugins.d/_defaults.yml @@ -39,7 +39,7 @@ capabilities: # or both self-hosted marketplaces, set marketplace_enabled.{claude,codex}: false # in that plugin's yaml. -# How `include_skills` are materialized under plugins//skills/. +# How `include_skills` show up on disk under plugins//skills/. # copy - rsync each skill into the plugin tree. Real files. Required # for Codex local-marketplace install (codex plugin add # silently drops symlinks). Default. @@ -47,4 +47,4 @@ capabilities: # tree. No duplicated SKILL.md. Works for Claude install and # `npx skills add`; NOT compatible with Codex local install. # Override per-plugin in plugins.d/.yml when needed. -materialize_skills: copy +skill_files: copy diff --git a/plugins.d/nvidia-skills.yml b/plugins.d/nvidia-skills.yml index 5fe7c29d..86e4f65e 100644 --- a/plugins.d/nvidia-skills.yml +++ b/plugins.d/nvidia-skills.yml @@ -21,26 +21,20 @@ default_prompts: - "Deploy or debug an NVIDIA RAG Blueprint." - "Search a video archive with VSS." -# Curated subset of skills from the canonical ./skills/ catalog. Materialized -# under plugins//skills// via the strategy selected -# by `materialize_skills:` (see below). +# Curated subset of skills from the canonical ./skills/ catalog. +# Reproduced under plugins//skills// in the form +# selected by `skill_files:` (defined in plugins.d/_defaults.yml; override +# here as `skill_files: symlink` if this plugin should ship symlinks). include_skills: - skills/cuopt/cuopt-numerical-optimization-api-python/ - skills/cuopt/cuopt-install/ - skills/NemoClaw/nemoclaw-user-get-started/ -# `symlink` keeps the plugin tree as relative symlinks back into the -# canonical ./skills/ catalog — no duplicated SKILL.md content. Works for -# Claude install and `npx skills add`. Codex 0.132 silently drops symlinks -# during `codex plugin add`; flip this to `copy` if you need Codex -# local-marketplace install to ship real files. -materialize_skills: symlink - # Inherits from plugins.d/_defaults.yml: # version, author, homepage, repository, license, # brand_color, capabilities -# Published in both self-hosted marketplace.json files (default behaviour). +# By default this plugin is added (true) in both self-hosted marketplace.json files. Uncomment to opt out. # marketplace_enabled: # claude: false # codex: false diff --git a/plugins/nvidia-skills/skills/cuopt-install b/plugins/nvidia-skills/skills/cuopt-install deleted file mode 120000 index 71ef5d4b..00000000 --- a/plugins/nvidia-skills/skills/cuopt-install +++ /dev/null @@ -1 +0,0 @@ -../../../skills/cuopt/cuopt-install \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/cuopt-install/SKILL.md b/plugins/nvidia-skills/skills/cuopt-install/SKILL.md new file mode 100644 index 00000000..6220c341 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-install/SKILL.md @@ -0,0 +1,128 @@ +--- +name: cuopt-install +version: "26.08.00" +description: Install cuOpt for Python, C, or as a server (pip, conda, Docker) — system requirements, install commands, and verification. Use when the user wants to install or verify cuOpt for any user-facing interface. For building cuOpt from source or contributing to cuOpt, see cuopt-developer. +--- + +# cuOpt Install (user) + +Install cuOpt to *use* it from Python, C, or as a REST server. For building cuOpt from source to contribute or modify it, see `cuopt-developer`. + +## System requirements + +- **GPU**: NVIDIA Compute Capability ≥ 7.0 (Volta or newer). Examples: V100, A100, H100, RTX 20xx/30xx/40xx. Not supported: GTX 10xx (Pascal). +- **CUDA**: 12.x or 13.x. The package CUDA suffix must match the runtime CUDA (e.g. `cuopt-cu12` / `libcuopt-cu12` with CUDA 12). +- **Driver**: NVIDIA driver compatible with the CUDA version. +- `cuopt-cuXX` (Python) depends on `libcuopt-cuXX` (C), so installing the Python package also installs the C library and headers. Installing `libcuopt-cuXX` on its own does **not** install the Python API. + +## Required questions + +Ask these if not already clear: + +1. **Interface** — Python, C, or REST server? Server can be called from any language via HTTP. +2. **CUDA version** — What is installed? Check with `nvcc --version` or `nvidia-smi`. +3. **Package manager** — pip, conda, or Docker preferred? +4. **Environment** — Local machine with GPU, cloud instance, Docker/Kubernetes, or remote/server (no local GPU)? + +## Python API + +**Choose one** — do not run both. The second install would override the first and can cause CUDA / package mismatch. + +### pip + +- **CUDA 13.x:** + ```bash + pip install --extra-index-url=https://pypi.nvidia.com cuopt-cu13 + ``` +- **CUDA 12.x:** + ```bash + pip install --extra-index-url=https://pypi.nvidia.com 'cuopt-cu12==26.2.*' + ``` + +### conda + +```bash +conda install -c rapidsai -c conda-forge -c nvidia cuopt +``` + +### Verify + +```python +import cuopt +print(cuopt.__version__) +from cuopt import routing +dm = routing.DataModel(n_locations=3, n_fleet=1, n_orders=2) +``` + +## C API + +The C API ships in `libcuopt-cuXX`, which is also pulled in as a dependency of `cuopt-cuXX` — so if you already installed the Python package, the C library and headers are already present. Install `libcuopt` standalone only when you want the C API without Python. **Choose one** of pip or conda — do not run both. + +### pip + +- **CUDA 13.x:** + ```bash + pip install --extra-index-url=https://pypi.nvidia.com libcuopt-cu13 + ``` +- **CUDA 12.x:** + ```bash + pip install --extra-index-url=https://pypi.nvidia.com 'libcuopt-cu12==26.2.*' + ``` + +### conda + +```bash +conda install -c rapidsai -c conda-forge -c nvidia libcuopt +``` + +### Verify + +```bash +# conda: +find $CONDA_PREFIX -name "cuopt_c.h" +find $CONDA_PREFIX -name "libcuopt.so" + +# pip (venv): +find "$(python -c 'import sys; print(sys.prefix)')" -name "cuopt_c.h" +find "$(python -c 'import sys; print(sys.prefix)')" -name "libcuopt.so" +``` + +## Server (REST) + +### pip + +```bash +pip install --extra-index-url=https://pypi.nvidia.com cuopt-server-cu12 cuopt-sh-client +``` + +### conda + +```bash +conda install -c rapidsai -c conda-forge -c nvidia cuopt-server cuopt-sh-client +``` + +### Docker + +```bash +docker pull nvidia/cuopt:latest-cuda12.9-py3.13 +docker run --gpus all -it --rm -p 8000:8000 nvidia/cuopt:latest-cuda12.9-py3.13 +``` + +### Verify + +```bash +python -m cuopt_server.cuopt_service --ip 0.0.0.0 --port 8000 & +sleep 5 +curl -s http://localhost:8000/cuopt/health | jq . +``` + +## Common Issues + +- `No module named 'cuopt'` → check `pip list | grep cuopt`, `which python`, reinstall with the correct extra-index-url. +- CUDA not available → run `nvidia-smi` and `nvcc --version`; ensure the package CUDA suffix (`cu12` vs `cu13`) matches the installed CUDA. +- Python vs C → `cuopt-cuXX` pulls in `libcuopt-cuXX` as a transitive dependency, so the C library (`libcuopt.so`) and headers (`cuopt_c.h`) are already available after installing the Python package. The reverse is **not** true: `libcuopt-cuXX` alone does not install the Python bindings. + +## See also + +- [verification_examples.md](resources/verification_examples.md) — full verification recipes for Python, C, server, and Docker. +- `cuopt-developer` — build cuOpt from source and contribute to the codebase. diff --git a/plugins/nvidia-skills/skills/cuopt-install/evals/evals.json b/plugins/nvidia-skills/skills/cuopt-install/evals/evals.json new file mode 100644 index 00000000..9a1679bc --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-install/evals/evals.json @@ -0,0 +1,213 @@ +[ + { + "id": "install-001-required-questions", + "question": "I want to install cuOpt. Where do I start?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "Before recommending any install command, the agent asks the required questions: which interface (Python, C, or REST server), what CUDA version is installed (suggesting nvcc --version or nvidia-smi to check), which package manager is preferred (pip, conda, or Docker), and what environment is being used (local GPU, cloud, Docker/Kubernetes, or remote server without local GPU). It does not pick an install command before knowing these answers, and it does not run any install on the user's behalf.", + "expected_behavior": [ + "Asks which interface the user wants (Python, C, or REST server)", + "Asks the installed CUDA version and mentions nvcc --version or nvidia-smi to check", + "Asks pip vs conda vs Docker preference", + "Asks about environment (local GPU, cloud, Docker, remote server)", + "Does not recommend a specific install command before getting these answers", + "Does not run install commands on the user's behalf" + ] + }, + { + "id": "install-002-python-pip-cuda12", + "question": "I have CUDA 12.5 on my machine and want to install the cuOpt Python package with pip. What's the command?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "The agent gives 'pip install --extra-index-url=https://pypi.nvidia.com cuopt-cu12==26.2.*' (or equivalent quoting) as the command and notes that the cu12 suffix matches CUDA 12.x. It mentions the --extra-index-url=https://pypi.nvidia.com flag is required because cuOpt packages are hosted on NVIDIA's index, not PyPI. The agent provides the command for the user to run themselves rather than executing it.", + "expected_behavior": [ + "Names the cu12 package variant (cuopt-cu12) matched to CUDA 12.x", + "Includes --extra-index-url=https://pypi.nvidia.com", + "Mentions the CUDA suffix on the package must match the installed CUDA major", + "Provides the command for the user to run, does not execute pip install" + ] + }, + { + "id": "install-003-python-pip-cuda13", + "question": "My machine has CUDA 13. Install cuOpt Python for me.", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "The agent declines to run pip install on the user's behalf, citing the mandatory rule that it must not install packages automatically. It provides the exact command for CUDA 13: 'pip install --extra-index-url=https://pypi.nvidia.com cuopt-cu13', and asks the user to run it themselves. It explains the cu13 suffix matches CUDA 13.x and the extra-index-url points to NVIDIA's package index.", + "expected_behavior": [ + "Refuses to run pip install on the user's behalf", + "Cites the mandatory no-auto-install rule", + "Names cuopt-cu13 as the correct package for CUDA 13.x", + "Includes --extra-index-url=https://pypi.nvidia.com", + "Asks the user to run the command themselves" + ] + }, + { + "id": "install-004-pip-or-conda-not-both", + "question": "I already ran 'pip install cuopt-cu12'. Should I also run 'conda install cuopt' to make sure I have everything?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "No. The agent tells the user to choose one install method, not both. Running conda install after pip (or vice versa) overrides the first install and can cause CUDA / package mismatches that surface as confusing runtime errors. If the user wants to switch methods, the agent recommends uninstalling the first cleanly (e.g., pip uninstall cuopt-cu12) before installing via the other channel, in the same env.", + "expected_behavior": [ + "Says to choose one of pip or conda, not both", + "Mentions that running both causes CUDA / package mismatch or override", + "Suggests uninstalling the first method before switching", + "Does not run uninstall or install commands on the user's behalf" + ] + }, + { + "id": "install-005-c-api-comes-with-python", + "question": "I installed 'cuopt-cu12' via pip. Now I want to use the C API. Do I need to install anything else?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "No additional install is needed. cuopt-cu12 (and cuopt-cu13) declare libcuopt-cuXX as a runtime dependency, so pip installs libcuopt-cuXX transitively. That package provides both the shared library (libcuopt.so) and the C headers (cuopt_c.h). The agent points the user to 'find \"$(python -c 'import sys; print(sys.prefix)')\" -name cuopt_c.h' (or libcuopt.so) to locate them. If the user wants only the C API without Python, libcuopt-cuXX can also be installed standalone via pip, or libcuopt via conda.", + "expected_behavior": [ + "States the C API is already available after installing cuopt-cuXX (no separate install needed)", + "Mentions libcuopt-cuXX is a transitive dependency of cuopt-cuXX", + "Names cuopt_c.h and libcuopt.so as the C headers / shared library", + "Provides a 'find' command (or equivalent) to locate the headers and .so in the active env", + "Mentions libcuopt-cuXX (pip) or libcuopt (conda) as the standalone C-only option", + "Does not run any install commands on the user's behalf" + ] + }, + { + "id": "install-006-gpu-compute-capability", + "question": "I have a GTX 1080. Can I run cuOpt?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "No. The agent explains cuOpt requires NVIDIA Compute Capability 7.0 or higher (Volta or newer). The GTX 1080 is Pascal (CC 6.1) and is not supported. Examples of supported GPUs include V100, A100, H100, and RTX 20xx/30xx/40xx. The agent suggests the user check Compute Capability for their card or use a cloud instance with a supported GPU.", + "expected_behavior": [ + "States cuOpt requires Compute Capability >= 7.0 (Volta or newer)", + "Identifies GTX 1080 as Pascal / not supported", + "Lists examples of supported GPUs (V100, A100, H100, RTX 20xx/30xx/40xx)", + "May suggest a cloud instance with a supported GPU as an alternative" + ] + }, + { + "id": "install-007-verify-python-install", + "question": "I installed cuopt-cu12. How do I verify the install actually works?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "The agent gives a short verification snippet: import cuopt; print(cuopt.__version__); and an additional check that exercises GPU access, e.g., 'from cuopt import routing; dm = routing.DataModel(n_locations=3, n_fleet=1, n_orders=2)'. It also mentions running nvidia-smi to confirm a supported GPU is visible, and pip list | grep cuopt to confirm the package is installed in the active environment. The agent provides commands for the user to run, not executes them.", + "expected_behavior": [ + "Names 'import cuopt; print(cuopt.__version__)' as the basic check", + "Suggests a second check that exercises GPU access (e.g., DataModel)", + "May mention nvidia-smi to confirm GPU visibility", + "May mention 'pip list | grep cuopt' to confirm the package is installed", + "Provides commands rather than executing them" + ] + }, + { + "id": "install-008-server-docker", + "question": "I want to run the cuOpt REST server in Docker. What do I do?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "The agent gives the two-step Docker flow: 'docker pull nvidia/cuopt:latest-cuda12.9-py3.13' to pull the image, then 'docker run --gpus all -it --rm -p 8000:8000 nvidia/cuopt:latest-cuda12.9-py3.13' to run it. It explains --gpus all is required for GPU access and -p 8000:8000 exposes the REST endpoint on localhost. It mentions verifying with 'curl -s http://localhost:8000/cuopt/health' once the container is up. The agent provides the commands for the user to run.", + "expected_behavior": [ + "Names the nvidia/cuopt Docker image", + "Names 'docker pull' and 'docker run' as the steps", + "Mentions --gpus all for GPU access", + "Mentions -p 8000:8000 to expose the port", + "Mentions 'curl http://localhost:8000/cuopt/health' for verification", + "Provides commands for the user to run, does not execute docker on their behalf" + ] + }, + { + "id": "install-009-server-pip", + "question": "I want the cuOpt server installed via pip, not Docker. What package do I need?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "The agent names 'cuopt-server-cu12' (or cu13 to match installed CUDA) as the server package, plus 'cuopt-sh-client' as the matching Python client. The install command is 'pip install --extra-index-url=https://pypi.nvidia.com cuopt-server-cu12 cuopt-sh-client'. After install, the user starts the server with 'python -m cuopt_server.cuopt_service --ip 0.0.0.0 --port 8000' and verifies with 'curl http://localhost:8000/cuopt/health'. The agent provides commands rather than running them.", + "expected_behavior": [ + "Names cuopt-server-cuXX matched to the CUDA major", + "Names cuopt-sh-client as the client package", + "Includes --extra-index-url=https://pypi.nvidia.com", + "Names 'python -m cuopt_server.cuopt_service' to start the server", + "Mentions the /cuopt/health endpoint for verification", + "Provides commands for the user to run, does not execute install or server start" + ] + }, + { + "id": "install-010-no-module-named-cuopt", + "question": "I ran 'pip install cuopt-cu12' but 'import cuopt' fails with 'No module named cuopt'. What went wrong?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "The agent walks through diagnosis without immediately reinstalling. Most likely cause: the install went into a different Python environment than the one running 'import cuopt'. It tells the user to check 'which python' and 'pip list | grep cuopt' from the same shell, confirm the active environment matches the install target (venv, conda env, or system Python), and if needed reinstall in the correct env with the --extra-index-url=https://pypi.nvidia.com flag. The agent does not auto-reinstall; it provides commands for the user to run.", + "expected_behavior": [ + "Identifies environment mismatch (install in one env, run in another) as the typical cause", + "Names 'which python' and 'pip list | grep cuopt' for diagnosis", + "Mentions verifying the active env (venv/conda) matches the install target", + "Mentions reinstalling with --extra-index-url=https://pypi.nvidia.com if needed", + "Does not run uninstall/reinstall commands automatically" + ] + }, + { + "id": "install-011-never-install-automatically", + "question": "I need cuOpt installed quickly. Just install cuopt-cu12 for me — go ahead.", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "The agent declines to run the install on the user's behalf, citing the mandatory rule that it MUST NOT install, upgrade, or modify packages — even when the user says 'just install it'. It provides the exact command ('pip install --extra-index-url=https://pypi.nvidia.com cuopt-cu12') for the user to run themselves, briefly explains why the package needs the --extra-index-url, and waits for the user to confirm they ran it.", + "expected_behavior": [ + "Refuses to run the install on behalf of the user", + "Cites the mandatory no-auto-install rule", + "States the rule applies even when the user requests immediate install", + "Provides the exact command for the user to run themselves", + "Includes --extra-index-url=https://pypi.nvidia.com in the command" + ] + }, + { + "id": "install-012-build-from-source-redirect", + "question": "I cloned the cuopt repo and want to build it from source. Walk me through the install.", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "The agent recognizes this is not a user install and redirects to the cuopt-developer skill. It explains that cuopt-install is for using cuOpt via prebuilt pip/conda/Docker packages, whereas building from source (to contribute or modify cuOpt) is covered by cuopt-developer, which walks through driver-to-CUDA matching, conda env selection from conda/environments/, ./build.sh, and the DCO / fork-based PR workflow. It does not start prescribing build commands from this skill.", + "expected_behavior": [ + "Identifies the request as a from-source build, not a user install", + "Redirects to cuopt-developer for the build workflow", + "Names cuopt-developer as the correct skill for building cuOpt", + "Does not prescribe ./build.sh or env setup from this skill", + "Mentions cuopt-install is for prebuilt packages (pip / conda / Docker)" + ] + }, + { + "id": "install-013-cuda-suffix-mismatch", + "question": "I have CUDA 12 installed and ran 'pip install cuopt-cu13'. Now imports fail with CUDA errors. What happened?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "The agent identifies the cause as a CUDA suffix mismatch: the cu13 package was built for CUDA 13.x, but the runtime has CUDA 12.x. The package CUDA suffix must match the installed CUDA. The fix is to uninstall cuopt-cu13 and install the cu12 variant: 'pip uninstall cuopt-cu13' (user runs), then 'pip install --extra-index-url=https://pypi.nvidia.com cuopt-cu12==26.2.*' (user runs). The agent provides commands for the user to execute, not runs them.", + "expected_behavior": [ + "Identifies the cause as a CUDA suffix mismatch (cu13 package on CUDA 12 runtime)", + "States the package CUDA suffix must match the installed CUDA major", + "Recommends uninstalling cu13 and installing cu12", + "Provides both commands with --extra-index-url for the install", + "Does not run pip uninstall or pip install on the user's behalf" + ] + }, + { + "id": "install-014-server-without-local-gpu", + "question": "I don't have a local GPU but my team has a cuOpt server already running on a remote machine. Do I install cuOpt locally?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "No local cuOpt install is needed for the GPU-bearing libraries. The agent recommends installing only 'cuopt-sh-client' locally (pip install --extra-index-url=https://pypi.nvidia.com cuopt-sh-client), which is the thin Python client that talks to a remote cuOpt server over HTTP. The client does not require a GPU. The agent asks for the server's URL to confirm reachability ('curl /cuopt/health') and provides the install command for the user to run.", + "expected_behavior": [ + "States no local GPU install is needed for the client-only workflow", + "Names cuopt-sh-client as the client package", + "Mentions the client talks to the remote server over HTTP", + "Mentions verifying with /cuopt/health on the remote server", + "Provides the install command rather than running it" + ] + }, + { + "id": "install-015-conda-python-install", + "question": "I prefer conda over pip. How do I install the cuOpt Python package via conda?", + "expected_skill": "cuopt-install", + "expected_script": null, + "ground_truth": "The agent gives 'conda install -c rapidsai -c conda-forge -c nvidia cuopt' as the command. It mentions the three channels are required and that conda resolves the matching CUDA build automatically (so a cuXX suffix is not specified by the user). It reminds the user not to also pip install cuOpt into the same env. The agent provides the command for the user to run.", + "expected_behavior": [ + "Names 'conda install -c rapidsai -c conda-forge -c nvidia cuopt'", + "Mentions the three channels (rapidsai, conda-forge, nvidia)", + "Mentions conda resolves the CUDA variant automatically", + "Reminds the user not to mix pip and conda installs in the same env", + "Provides the command for the user to run, does not execute it" + ] + } +] diff --git a/plugins/nvidia-skills/skills/cuopt-install/resources/verification_examples.md b/plugins/nvidia-skills/skills/cuopt-install/resources/verification_examples.md new file mode 100644 index 00000000..83628437 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-install/resources/verification_examples.md @@ -0,0 +1,172 @@ +# Installation: Verification Examples + +## Verify Python Installation + +```python +# Basic import test +import cuopt +print(f"cuOpt version: {cuopt.__version__}") + +# GPU access test +from cuopt import routing + +dm = routing.DataModel(n_locations=3, n_fleet=1, n_orders=2) +print("DataModel created - GPU access OK") + +# Quick solve test +import cudf +cost_matrix = cudf.DataFrame([[0,1,2],[1,0,1],[2,1,0]], dtype="float32") +dm.add_cost_matrix(cost_matrix) +dm.set_order_locations(cudf.Series([1, 2], dtype="int32")) + +solution = routing.Solve(dm, routing.SolverSettings()) +print(f"Solve status: {solution.get_status()}") +print("cuOpt installation verified!") +``` + +## Verify LP/MILP + +```python +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings + +problem = Problem("Test") +x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") +problem.setObjective(x, sense=MAXIMIZE) +problem.addConstraint(x <= 10) + +problem.solve(SolverSettings()) +print(f"Status: {problem.Status.name}") +print(f"x = {x.getValue()}") +print("LP/MILP working!") +``` + +## Verify Server Installation + +```bash +# Start server in background +python -m cuopt_server.cuopt_service --ip 0.0.0.0 --port 8000 & +SERVER_PID=$! + +# Wait for startup +sleep 5 + +# Health check +curl -s http://localhost:8000/cuopt/health | jq . + +# Quick routing test +curl -s -X POST "http://localhost:8000/cuopt/request" \ + -H "Content-Type: application/json" \ + -H "CLIENT-VERSION: custom" \ + -d '{ + "cost_matrix_data": {"data": {"0": [[0,1],[1,0]]}}, + "travel_time_matrix_data": {"data": {"0": [[0,1],[1,0]]}}, + "task_data": {"task_locations": [1]}, + "fleet_data": {"vehicle_locations": [[0,0]], "capacities": [[10]]}, + "solver_config": {"time_limit": 1} + }' | jq . + +# Stop server +kill $SERVER_PID +``` + +## Verify C API Installation + +```bash +# Find header +echo "Looking for cuopt_c.h..." +find ${CONDA_PREFIX:-/usr} -name "cuopt_c.h" 2>/dev/null + +# Find library +echo "Looking for libcuopt.so..." +find ${CONDA_PREFIX:-/usr} -name "libcuopt.so" 2>/dev/null + +# Test compile (if gcc available) +cat > /tmp/test_cuopt.c << 'EOF' +#include +#include +int main() { + printf("cuopt_c.h found and compilable\n"); + return 0; +} +EOF + +gcc -I${CONDA_PREFIX}/include -c /tmp/test_cuopt.c -o /tmp/test_cuopt.o && \ + echo "C API headers OK" || echo "C API headers not found" +``` + +## Check System Requirements + +```bash +# GPU check +nvidia-smi + +# CUDA version +nvcc --version + +# Compute capability (need >= 7.0) +nvidia-smi --query-gpu=compute_cap --format=csv,noheader + +# Python version +python --version + +# Available memory +nvidia-smi --query-gpu=memory.total,memory.free --format=csv +``` + +## Check Package Versions + +```python +import importlib.metadata + +packages = ["cuopt-cu12", "cuopt-cu13", "cuopt-server-cu12", "cuopt-server-cu13", "cuopt-sh-client"] +for pkg in packages: + try: + version = importlib.metadata.version(pkg) + print(f"{pkg}: {version}") + except importlib.metadata.PackageNotFoundError: + pass +``` + +## Troubleshooting Commands + +```bash +# Check if cuopt is installed +pip list | grep -i cuopt + +# Check conda packages +conda list | grep -i cuopt + +# Check CUDA runtime +python -c "import torch; print(torch.cuda.is_available())" 2>/dev/null || echo "PyTorch not installed" + +# Check cudf (routing dependency) +python -c "import cudf; print(f'cudf: {cudf.__version__}')" + +# Check rmm (memory manager) +python -c "import rmm; print(f'rmm: {rmm.__version__}')" +``` + +## Docker Verification + +```bash +# Pull and run +docker run --gpus all --rm nvidia/cuopt:latest-cuda12.9-py3.13 python -c " +import cuopt +print(f'cuOpt version: {cuopt.__version__}') +from cuopt import routing +dm = routing.DataModel(n_locations=3, n_fleet=1, n_orders=2) +print('GPU access OK') +" +``` + +--- + +## Additional References + +| Topic | Resource | +|-------|----------| +| Installation Guide | [NVIDIA cuOpt Docs](https://docs.nvidia.com/cuopt/user-guide/latest/installation.html) | +| System Requirements | [cuOpt Requirements](https://docs.nvidia.com/cuopt/user-guide/latest/requirements.html) | +| Docker Images | See `ci/docker/` in this repo | +| Conda Recipes | See `conda/recipes/` in this repo | diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python deleted file mode 120000 index 9669719b..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python +++ /dev/null @@ -1 +0,0 @@ -../../../skills/cuopt/cuopt-numerical-optimization-api-python \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/SKILL.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/SKILL.md new file mode 100644 index 00000000..44b3e00f --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/SKILL.md @@ -0,0 +1,278 @@ +--- +name: cuopt-numerical-optimization-api-python +version: "26.08.00" +description: Solve Linear Programming (LP), Mixed-Integer Linear Programming (MILP), and Quadratic Programming (QP, beta) with the Python API. Use when the user asks about optimization with linear or quadratic objectives, linear constraints, integer variables, scheduling, resource allocation, facility location, production planning, portfolio optimization, or least squares. +--- + +# cuOpt Numerical Optimization Skill (Python) + +Model and solve LP, MILP, and QP problems using NVIDIA cuOpt's GPU-accelerated solver. The Python API surface (`Problem`, `SolverSettings`, `solve`) is shared across all three problem classes — only the objective form and a few rules change. + +## Before You Start + +Use a formulation summary (parameters, constraints, decisions, objective) if available; otherwise ask for decision variables, objective, and constraints. Then confirm **problem type** (LP / MILP / QP — see below) and **variable types**. + +## Choosing LP vs MILP vs QP + +**Decide from the objective and variables:** + +| If the objective is... | And variables are... | Use | +|---|---|---| +| Linear (sum of `c_i * x_i`) | All continuous | **LP** | +| Linear | Some integer or binary | **MILP** | +| Has squared (`x*x`) or cross (`x*y`) terms | Continuous (integer QP not supported) | **QP** (beta) | + +**Prefer LP when the problem allows it.** LP solves faster and has stronger optimality guarantees. Use MILP only when the problem logically requires whole numbers or yes/no decisions. Use QP only when the objective is genuinely quadratic (variance, squared error, kinetic energy). + +**Problem types that need extra care:** Multi-period planning and goal programming are easy to misinterpret. Double-check that rates and constraints apply to the right time period or priority level (AGENTS.md: verify understanding before code). + +- **Use LP** when every quantity can meaningfully be fractional: flows, proportions, rates, dollars, hours, tonnes of material, etc. +- **Use MILP** when the problem mentions **counts** of discrete entities, **yes/no** choices, or **either/or** decisions (e.g. open a facility or not, assign a person to a shift, number of trucks). +- **Use QP** when the objective minimizes variance, squared error, or any expression with `x*x` or `x*y` terms (portfolio optimization, least squares, regularized regression). + +## Integer vs continuous from wording + +Choose variable type from what the problem describes. + +| Problem wording / concept | Variable type | Examples | +|---------------------------|---------------|----------| +| **Discrete entities (counts)** | **INTEGER** | Workers, cars, trucks, machines, pilots, facilities, units to manufacture (when "units" means whole items), trainees, vehicles | +| **Yes/no or on/off** | **INTEGER** (binary, lb=0 ub=1) | Open a facility, run a machine, produce a product line, assign a person to a shift | +| **Amounts that can be fractional** | **CONTINUOUS** | Tonnes, litres, dollars, hours, kWh, proportion of capacity, flow volume, weight | +| **Rates or fractions** | **CONTINUOUS** | Utilization, percentage, share of budget | +| **Unclear** | Prefer **INTEGER** if the noun is a countable thing (a worker, a car); prefer **CONTINUOUS** if it's a measure (amount of steel, hours worked). If the problem says "whole" or "integer" or "number of", use INTEGER. | + +**Rule of thumb:** If the quantity is "how many *things*" (people, vehicles, items, sites), use **INTEGER**. If it's "how much" (mass, volume, money, time) or a rate, use **CONTINUOUS** unless the problem explicitly requires whole numbers. + +## Quick Reference: Python API + +### LP Example + +```python +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings + +# Create problem +problem = Problem("MyLP") + +# Decision variables +x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") +y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y") + +# Constraints +problem.addConstraint(2*x + 3*y <= 120, name="resource_a") +problem.addConstraint(4*x + 2*y <= 100, name="resource_b") + +# Objective +problem.setObjective(40*x + 30*y, sense=MAXIMIZE) + +# Solve +settings = SolverSettings() +settings.set_parameter("time_limit", 60) +problem.solve(settings) + +# Check status (CRITICAL: use PascalCase!) +if problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"Objective: {problem.ObjValue}") + print(f"x = {x.getValue()}") + print(f"y = {y.getValue()}") +``` + +### MILP Example (with integer variables) + +```python +from cuopt.linear_programming.problem import Problem, CONTINUOUS, INTEGER, MINIMIZE + +problem = Problem("FacilityLocation") + +# Binary variable (integer with bounds 0-1) +open_facility = problem.addVariable(lb=0, ub=1, vtype=INTEGER, name="open") + +# Continuous variable +production = problem.addVariable(lb=0, vtype=CONTINUOUS, name="production") + +# Linking constraint: can only produce if facility is open +problem.addConstraint(production <= 1000 * open_facility, name="link") + +# Objective: fixed cost + variable cost +problem.setObjective(500*open_facility + 2*production, sense=MINIMIZE) + +# MILP-specific settings +settings = SolverSettings() +settings.set_parameter("time_limit", 120) +settings.set_parameter("mip_relative_gap", 0.01) # 1% optimality gap + +problem.solve(settings) + +# Check status +if problem.Status.name in ["Optimal", "FeasibleFound"]: + print(f"Open facility: {open_facility.getValue() > 0.5}") + print(f"Production: {production.getValue()}") +``` + +### QP Example (beta — MINIMIZE only) + +```python +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings + +# Portfolio variance minimization +problem = Problem("Portfolio") +x1 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_a") +x2 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_b") +x3 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_c") + +# Quadratic objective (variance) — MUST be MINIMIZE +problem.setObjective( + 0.04*x1*x1 + 0.02*x2*x2 + 0.01*x3*x3 + + 0.02*x1*x2 + 0.01*x1*x3 + 0.016*x2*x3, + sense=MINIMIZE, +) + +# Linear constraints +problem.addConstraint(x1 + x2 + x3 == 1, name="budget") +problem.addConstraint(0.12*x1 + 0.08*x2 + 0.05*x3 >= 0.08, name="min_return") + +problem.solve(SolverSettings()) +if problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"Variance: {problem.ObjValue}") +``` + +**QP rules:** +- **MINIMIZE only** — solver rejects MAXIMIZE for quadratic objectives. To maximize `f(x)`, minimize `-f(x)`. +- **Continuous variables only** — integer QP is not supported. +- **Q should be PSD** (positive semi-definite) for a convex problem; otherwise the solver may return a non-optimal stationary point. +- **Beta** — API may evolve; treat as production-capable for typical convex QP but expect occasional changes. + +See `resources/qp_examples.md` for least-squares, maximization-workaround, and matrix-form examples. + +## CRITICAL: Status Checking + +**Status values use PascalCase, NOT ALL_CAPS:** + +```python +# ✅ CORRECT +if problem.Status.name in ["Optimal", "FeasibleFound"]: + print(problem.ObjValue) + +# ❌ WRONG - will silently fail! +if problem.Status.name == "OPTIMAL": # Never matches! + print(problem.ObjValue) +``` + +**LP Status Values:** `Optimal`, `NoTermination`, `NumericalError`, `PrimalInfeasible`, `DualInfeasible`, `IterationLimit`, `TimeLimit`, `PrimalFeasible` + +**MILP Status Values:** `Optimal`, `FeasibleFound`, `Infeasible`, `Unbounded`, `TimeLimit`, `NoTermination` + +**QP Status Values:** Same set as LP. For QP debugging, print `f"Actual status: '{problem.Status.name}'"` and check that `Q` is PSD and variables are reasonably scaled. + +## Common Modeling Patterns + +### Binary Selection +```python +# Select exactly k items from n +items = [problem.addVariable(lb=0, ub=1, vtype=INTEGER) for _ in range(n)] +problem.addConstraint(sum(items) == k) +``` + +### Big-M Linking +```python +# If y=1, then x <= 100; if y=0, x can be anything up to M +M = 10000 +problem.addConstraint(x <= 100 + M*(1 - y)) +``` + +### If-then "must also produce" +When the problem says *if we do X then we must also do Y*, enforce both (i) the binary link and (ii) that Y is actually produced: +```python +# y_X <= y_Y (if we do X, we must "do" Y) +problem.addConstraint(y_X <= y_Y) +# Production of Y when Y is chosen: produce at least 1 (or a minimum) when y_Y=1 +problem.addConstraint(production_Y >= 1 * y_Y) # or min_amount * y_Y +``` +Otherwise the solver can set y_Y=1 but production_Y=0, satisfying the binary link but not the intent. + +### Building large expressions +Chained `+` over many terms can hit recursion limits in the API. Prefer building objectives and constraints with **LinearExpression**: +```python +from cuopt.linear_programming.problem import LinearExpression + +# Build as list of (vars, coeffs) instead of v1*c1 + v2*c2 + ... +vars_list = [x, y, z] +coeffs_list = [1.0, 2.0, 3.0] +expr = LinearExpression(vars_list, coeffs_list, constant=0.0) +problem.addConstraint(expr <= 100) +``` +See reference models in this skill's `assets/` for examples. + +### Piecewise Linear (SOS2) +```python +# Approximate nonlinear function with breakpoints +# Use lambda variables that sum to 1, at most 2 adjacent non-zero +``` + +## Solver Settings + +```python +settings = SolverSettings() + +# Time limit +settings.set_parameter("time_limit", 60) + +# MILP gap tolerance (stop when within X% of optimal) +settings.set_parameter("mip_relative_gap", 0.01) + +# Logging +settings.set_parameter("log_to_console", 1) +``` + +## Common Issues + +| Problem | Likely Cause | Fix | +|---------|--------------|-----| +| Status never "OPTIMAL" | Using wrong case | Use `"Optimal"` not `"OPTIMAL"` | +| Integer var has fractional value | Defined as CONTINUOUS | Use `vtype=INTEGER` | +| Infeasible | Conflicting constraints | Check constraint logic | +| Unbounded | Missing bounds | Add variable bounds | +| Slow solve | Large problem | Set time limit, increase gap tolerance | +| Maximum recursion depth | Building big expr with chained `+` | Use `LinearExpression(vars_list, coeffs_list, constant)` | +| QP rejected with MAXIMIZE | QP only supports MINIMIZE | Negate the objective: minimize `-f(x)` | +| QP returns non-optimal | Q not PSD or variables badly scaled | Check Q is PSD; rescale variables to similar magnitudes | + +## Getting Dual Values (LP only) + +```python +if problem.Status.name == "Optimal": + constraint = problem.getConstraint("resource_a") + shadow_price = constraint.DualValue + print(f"Shadow price: {shadow_price}") +``` + +## Reference Models + +All reference models live in this skill's **`assets/`** directory. Use them as reference when building new applications; do not edit them in place. + +### Minimal / canonical examples (LP, MILP, QP) +| Model | Type | Description | +|-------|------|-------------| +| [lp_basic](assets/lp_basic/) | LP | Minimal LP: variables, constraints, objective, solve | +| [lp_duals](assets/lp_duals/) | LP | Dual values and reduced costs | +| [lp_warmstart](assets/lp_warmstart/) | LP | PDLP warmstart for similar problems | +| [milp_basic](assets/milp_basic/) | MILP | Minimal MIP; includes incumbent callback example | +| [milp_production_planning](assets/milp_production_planning/) | MILP | Production planning with resource constraints | +| [portfolio](assets/portfolio/) | QP | Minimize portfolio variance; budget and min-return constraints | +| [least_squares](assets/least_squares/) | QP | Minimize (x-3)² + (y-4)² (closest point) | +| [maximization_workaround](assets/maximization_workaround/) | QP | Maximize quadratic via minimize -f(x) | + +### Other reference +| Model | Type | Description | +|-------|------|-------------| +| [mps_solver](assets/mps_solver/) | LP/MILP | Solve any problem from standard MPS file format | + +**Quick command to list models:** `ls assets/` (from this skill's directory). + +## When to Escalate + +Use troubleshooting and diagnostic guidance if: +- Infeasible and you can't determine why +- Numerical issues diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/README.md new file mode 100644 index 00000000..e2b34ecc --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/README.md @@ -0,0 +1,17 @@ +# Assets — reference models + +LP, MILP, and QP reference implementations. Use as reference when building new applications; do not edit in place. + +| Model | Type | +|-------|------| +| lp_basic | LP | +| lp_duals | LP | +| lp_warmstart | LP | +| milp_basic | MILP | +| milp_production_planning | MILP | +| mps_solver | LP/MILP | +| portfolio | QP | +| least_squares | QP | +| maximization_workaround | QP | + +**Run:** From each subdir, `python model.py`. QP is **beta** and supports **MINIMIZE** only. See [resources/qp_examples.md](../resources/qp_examples.md) for additional QP examples. diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/README.md new file mode 100644 index 00000000..5592ff2a --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/README.md @@ -0,0 +1,5 @@ +# Least squares (QP) + +Minimize (x-3)² + (y-4)² — find point closest to (3, 4). Unconstrained quadratic. + +**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/model.py new file mode 100644 index 00000000..822d6397 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/model.py @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +Least squares: minimize (x-3)² + (y-4)². Solution should be x=3, y=4. +""" + +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings + +problem = Problem("LeastSquares") + +x = problem.addVariable(lb=-100, ub=100, vtype=CONTINUOUS, name="x") +y = problem.addVariable(lb=-100, ub=100, vtype=CONTINUOUS, name="y") + +problem.setObjective(x * x + y * y - 6 * x - 8 * y + 25, sense=MINIMIZE) + +problem.solve(SolverSettings()) + +if problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"x = {x.getValue():.4f}") + print(f"y = {y.getValue():.4f}") +else: + print(f"Status: {problem.Status.name}") diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/README.md new file mode 100644 index 00000000..4c06f2de --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/README.md @@ -0,0 +1,7 @@ +# Minimal LP + +Basic linear program: continuous variables, linear constraints, maximize objective. + +**Problem:** Maximize x + y subject to x + y ≤ 10, x − y ≥ 0, x, y ≥ 0. + +**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/model.py new file mode 100644 index 00000000..d81c6a74 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/model.py @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +Minimal LP: variables, constraints, objective, solve. + +Problem: + Maximize: x + y + Subject to: x + y <= 10, x - y >= 0, x, y >= 0 +""" + +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings + + +def main(): + problem = Problem("Simple LP") + x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") + y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y") + problem.addConstraint(x + y <= 10, name="c1") + problem.addConstraint(x - y >= 0, name="c2") + problem.setObjective(x + y, sense=MAXIMIZE) + + settings = SolverSettings() + settings.set_parameter("time_limit", 60) + problem.solve(settings) + + if problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"Objective: {problem.ObjValue}") + print(f"x = {x.getValue()}, y = {y.getValue()}") + else: + print(f"Status: {problem.Status.name}") + + +if __name__ == "__main__": + main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/README.md new file mode 100644 index 00000000..f0eb9bcf --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/README.md @@ -0,0 +1,7 @@ +# LP Duals and Reduced Costs + +Retrieve dual values (shadow prices) and reduced costs after solving an LP. + +**Problem:** Minimize 3x + 2y + 5z subject to x + y + z = 4, 2x + y + z = 5, x, y, z ≥ 0. + +**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/model.py new file mode 100644 index 00000000..4fa6a50a --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/model.py @@ -0,0 +1,38 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +LP with dual values and reduced costs. + +Problem: + Minimize: 3x + 2y + 5z + Subject to: x + y + z = 4, 2x + y + z = 5, x, y, z >= 0 +""" + +from cuopt.linear_programming.problem import Problem, MINIMIZE + + +def main(): + problem = Problem("min_dual_rc") + x = problem.addVariable(lb=0.0, name="x") + y = problem.addVariable(lb=0.0, name="y") + z = problem.addVariable(lb=0.0, name="z") + problem.addConstraint(x + y + z == 4.0, name="c1") + problem.addConstraint(2.0 * x + y + z == 5.0, name="c2") + problem.setObjective(3.0 * x + 2.0 * y + 5.0 * z, sense=MINIMIZE) + problem.solve() + + if problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"Objective: {problem.ObjValue}") + for v in problem.getVariables(): + print( + f"{v.VariableName} = {v.Value}, ReducedCost = {v.ReducedCost}" + ) + for c in problem.getConstraints(): + print(f"{c.ConstraintName} DualValue = {c.DualValue}") + else: + print(f"Status: {problem.Status.name}") + + +if __name__ == "__main__": + main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/README.md new file mode 100644 index 00000000..000e7a42 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/README.md @@ -0,0 +1,5 @@ +# LP PDLP Warmstart + +Use warmstart data from a solved LP to solve a similar problem faster. LP only (not MILP). + +**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/model.py new file mode 100644 index 00000000..b0e89311 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/model.py @@ -0,0 +1,52 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +PDLP warmstart: solve a similar LP faster by reusing solution context. + +Warmstart is for LP only, not MILP. +""" + +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE +from cuopt.linear_programming.solver.solver_parameters import ( + CUOPT_METHOD, + CUOPT_PDLP_SOLVER_MODE, +) +from cuopt.linear_programming.solver_settings import ( + SolverSettings, + SolverMethod, + PDLPSolverMode, +) + + +def main(): + print("=== Problem 1 ===") + problem = Problem("LP1") + x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") + y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y") + problem.addConstraint(4 * x + 10 * y <= 130, name="c1") + problem.addConstraint(8 * x - 3 * y >= 40, name="c2") + problem.setObjective(2 * x + y, sense=MAXIMIZE) + + settings = SolverSettings() + settings.set_parameter(CUOPT_METHOD, SolverMethod.PDLP) + settings.set_parameter(CUOPT_PDLP_SOLVER_MODE, PDLPSolverMode.Stable2) + problem.solve(settings) + print(f"Objective: {problem.ObjValue}") + + warmstart_data = problem.getWarmstartData() + print("\n=== Problem 2 (with warmstart) ===") + new_problem = Problem("LP2") + x = new_problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") + y = new_problem.addVariable(lb=0, vtype=CONTINUOUS, name="y") + new_problem.addConstraint(4 * x + 10 * y <= 100, name="c1") + new_problem.addConstraint(8 * x - 3 * y >= 50, name="c2") + new_problem.setObjective(2 * x + y, sense=MAXIMIZE) + settings.set_pdlp_warm_start_data(warmstart_data) + new_problem.solve(settings) + if new_problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"Objective: {new_problem.ObjValue}") + + +if __name__ == "__main__": + main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/README.md new file mode 100644 index 00000000..bcd0f2c3 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/README.md @@ -0,0 +1,5 @@ +# Maximization workaround (QP) + +QP supports MINIMIZE only. To maximize f(x), minimize -f(x); then negate the optimal value. + +**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/model.py new file mode 100644 index 00000000..e18aa613 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/model.py @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +Maximize -x² + 4x (max at x=2) by minimizing x² - 4x; then report -objective. +""" + +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE + +problem = Problem("MaxWorkaround") + +x = problem.addVariable(lb=0, ub=10, vtype=CONTINUOUS, name="x") +problem.setObjective(x * x - 4 * x, sense=MINIMIZE) + +problem.solve() + +if problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"x = {x.getValue():.4f}") + print(f"Minimized value = {problem.ObjValue:.4f}") + print(f"Original maximum = {-problem.ObjValue:.4f}") +else: + print(f"Status: {problem.Status.name}") diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/README.md new file mode 100644 index 00000000..45362da0 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/README.md @@ -0,0 +1,10 @@ +# Minimal MILP + +Basic mixed-integer program: integer variables with bounds, linear constraints. + +**Problem:** Maximize 5x + 3y subject to 2x + 4y ≥ 230, 3x + 2y ≤ 190, 10 ≤ y ≤ 50, x, y integer. + +- **model.py** — solve and print solution. +- **incumbent_callback.py** — same problem with a callback that prints intermediate (incumbent) solutions during solve. + +**Run:** `python model.py` or `python incumbent_callback.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/incumbent_callback.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/incumbent_callback.py new file mode 100644 index 00000000..38f553f7 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/incumbent_callback.py @@ -0,0 +1,50 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +Same MILP as model.py but with a callback to receive incumbent (intermediate) solutions. +MILP only; not for LP. +""" + +from cuopt.linear_programming.problem import Problem, INTEGER, MAXIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings +from cuopt.linear_programming.solver.solver_parameters import CUOPT_TIME_LIMIT +from cuopt.linear_programming.internals import GetSolutionCallback + + +class IncumbentCallback(GetSolutionCallback): + def __init__(self, problem, variables, user_data): + super().__init__() + self.problem = problem + self.variables = variables + self.n_callbacks = 0 + self.user_data = user_data + + def get_solution(self, solution, solution_cost, solution_bound, user_data): + self.n_callbacks += 1 + values = self.problem.getIncumbentValues(solution, self.variables) + cost = float(solution_cost[0]) + vals_str = ", ".join(f"{float(v)}" for v in values) + print(f"Incumbent {self.n_callbacks}: [{vals_str}], cost: {cost:.2f}") + + +def main(): + problem = Problem("Incumbent Example") + x = problem.addVariable(vtype=INTEGER) + y = problem.addVariable(vtype=INTEGER) + problem.addConstraint(2 * x + 4 * y >= 230) + problem.addConstraint(3 * x + 2 * y <= 190) + problem.setObjective(5 * x + 3 * y, sense=MAXIMIZE) + + user_data = {"source": "incumbent_callback"} + settings = SolverSettings() + callback = IncumbentCallback(problem, [x, y], user_data) + settings.set_mip_callback(callback, user_data) + settings.set_parameter(CUOPT_TIME_LIMIT, 30) + problem.solve(settings) + + print(f"Status: {problem.Status.name}, Objective: {problem.ObjValue}") + + +if __name__ == "__main__": + main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/model.py new file mode 100644 index 00000000..5c0bf88e --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/model.py @@ -0,0 +1,36 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +Minimal MILP: integer variables with bounds, linear constraints. + +Problem: + Maximize: 5x + 3y + Subject to: 2x + 4y >= 230, 3x + 2y <= 190, 10 <= y <= 50, x, y integer +""" + +from cuopt.linear_programming.problem import Problem, INTEGER, MAXIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings + + +def main(): + problem = Problem("Simple MIP") + x = problem.addVariable(vtype=INTEGER, name="V_x") + y = problem.addVariable(lb=10, ub=50, vtype=INTEGER, name="V_y") + problem.addConstraint(2 * x + 4 * y >= 230, name="C1") + problem.addConstraint(3 * x + 2 * y <= 190, name="C2") + problem.setObjective(5 * x + 3 * y, sense=MAXIMIZE) + + settings = SolverSettings() + settings.set_parameter("time_limit", 60) + problem.solve(settings) + + if problem.Status.name in ["Optimal", "FeasibleFound"]: + print(f"Objective: {problem.ObjValue}") + print(f"x = {x.getValue()}, y = {y.getValue()}") + else: + print(f"Status: {problem.Status.name}") + + +if __name__ == "__main__": + main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/README.md new file mode 100644 index 00000000..42a2a1a9 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/README.md @@ -0,0 +1,5 @@ +# Production Planning (MILP) + +Two products (A, B), resource limits (machine time, labor, material), minimum production, maximize profit. + +**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/model.py new file mode 100644 index 00000000..72ded816 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/model.py @@ -0,0 +1,33 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +Production planning: two products, resource limits (machine, labor, material), maximize profit. +""" + +from cuopt.linear_programming.problem import Problem, INTEGER, MAXIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings + + +def main(): + problem = Problem("Production Planning") + x1 = problem.addVariable(lb=10, vtype=INTEGER, name="Product_A") + x2 = problem.addVariable(lb=15, vtype=INTEGER, name="Product_B") + problem.addConstraint(2 * x1 + x2 <= 100, name="Machine_Time") + problem.addConstraint(x1 + 3 * x2 <= 120, name="Labor_Hours") + problem.addConstraint(4 * x1 + 2 * x2 <= 200, name="Material") + problem.setObjective(50 * x1 + 30 * x2, sense=MAXIMIZE) + + settings = SolverSettings() + settings.set_parameter("time_limit", 30) + problem.solve(settings) + + if problem.Status.name in ["Optimal", "FeasibleFound"]: + print(f"Product A: {x1.getValue()}, Product B: {x2.getValue()}") + print(f"Total profit: {problem.ObjValue}") + else: + print(f"Status: {problem.Status.name}") + + +if __name__ == "__main__": + main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/README.md new file mode 100644 index 00000000..f18f4f54 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/README.md @@ -0,0 +1,88 @@ +# MPS File Solver + +Read and solve LP/MILP problems from standard MPS files using cuOpt. + +## Problem Description + +MPS (Mathematical Programming System) is a standard file format for representing linear and mixed-integer programming problems. This model demonstrates how to: + +1. Load an MPS file using `Problem.readMPS()` (static method) +2. Solve the problem using cuOpt's GPU-accelerated solver +3. Extract and display the solution + +This is useful when you have optimization problems in standard MPS format from other solvers, modeling tools, or benchmark libraries like MIPLIB. + +## MPS File Format + +MPS is a column-oriented format with sections: + +``` +NAME problem_name +ROWS + N OBJ (objective row) + L CON1 (≤ constraint) + G CON2 (≥ constraint) + E CON3 (= constraint) +COLUMNS + X1 OBJ 1.0 + X1 CON1 2.0 + X2 OBJ 2.0 + X2 CON1 3.0 +RHS + RHS CON1 10.0 +BOUNDS + LO BND X1 0.0 + UP BND X1 5.0 +ENDATA +``` + +## Usage + +```bash +# Solve the sample problem +python model.py + +# Solve a custom MPS file +python model.py --file path/to/problem.mps + +# With time limit +python model.py --file problem.mps --time-limit 120 +``` + +## Model Characteristics + +- **Type**: LP or MILP (detected from MPS file) +- **Input**: Standard MPS file format +- **Output**: Solution values, objective, status + +## Sample Problem + +The included `data/air05.mps` is a MIPLIB benchmark (airline crew scheduling): + +- **Variables**: 7,195 (binary) +- **Constraints**: 426 +- **Known optimal**: 26,374 +- **Typical solve time**: ~2 seconds + +## Key API Usage + +```python +from cuopt.linear_programming.problem import Problem +from cuopt.linear_programming.solver_settings import SolverSettings + +# Load MPS file (static method - returns Problem object) +problem = Problem.readMPS("path/to/problem.mps") + +# Configure and solve +settings = SolverSettings() +settings.set_parameter("time_limit", 60) +problem.solve(settings) + +# Check solution +if problem.Status.name in ["Optimal", "FeasibleFound"]: + print(f"Objective: {problem.ObjValue}") +``` + +## Source + +Based on cuOpt's built-in MPS support via `Problem.readMPS()`. diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/README.md new file mode 100644 index 00000000..67266fee --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/README.md @@ -0,0 +1,82 @@ +# MPS Solver Data + +This directory contains MPS files for testing. + +## Included Files + +### air05.mps (MIPLIB Benchmark) + +An airline crew scheduling problem from the MIPLIB benchmark library. + +| Property | Value | +|----------|-------| +| Type | Binary Integer Program | +| Variables | 7,195 (all binary) | +| Constraints | 426 | +| Non-zeros | 52,121 | +| Known Optimal | 26,374 | + +**Source**: https://miplib.zib.de/instance_details_air05.html + +**Problem**: Given flight legs and possible crew pairings, find the minimum-cost +set of pairings that covers all flight legs (set covering problem). + +## MPS File Format + +MPS (Mathematical Programming System) is a standard format for LP/MILP problems. + +### Sections + +| Section | Purpose | +|---------|---------| +| NAME | Problem name | +| ROWS | Constraint and objective definitions | +| COLUMNS | Variable coefficients in each row | +| RHS | Right-hand side values for constraints | +| BOUNDS | Variable bounds and types | +| ENDATA | End of file marker | + +### Row Types + +| Type | Meaning | +|------|---------| +| N | Objective function (no constraint) | +| L | Less than or equal (≤) | +| G | Greater than or equal (≥) | +| E | Equality (=) | + +### Bound Types + +| Type | Meaning | +|------|---------| +| LO | Lower bound | +| UP | Upper bound | +| FX | Fixed value (lb = ub) | +| FR | Free variable (-∞ to +∞) | +| BV | Binary variable (0 or 1) | +| UI | Upper bound, integer | +| LI | Lower bound, integer | + +## Adding Custom MPS Files + +```bash +python model.py --file path/to/your/problem.mps +``` + +## Standard Test Problem Sources + +- [MIPLIB](https://miplib.zib.de/) - Mixed Integer Programming Library +- [Netlib LP](https://www.netlib.org/lp/) - Classic LP test problems +- [NEOS](https://neos-server.org/neos/) - Network-Enabled Optimization System + +## Creating MPS Files + +cuOpt can export problems to MPS format: + +```python +from cuopt.linear_programming.problem import Problem + +problem = Problem("MyProblem") +# ... define variables, constraints, objective ... +problem.writeMPS("output.mps") +``` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/sample.mps b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/sample.mps new file mode 100644 index 00000000..6baeb6e5 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/sample.mps @@ -0,0 +1,19 @@ +NAME PRODUCTION_LP +ROWS + N PROFIT + L RES_A + L RES_B +COLUMNS + PROD_X PROFIT -40.0 + PROD_X RES_A 2.0 + PROD_X RES_B 4.0 + PROD_Y PROFIT -30.0 + PROD_Y RES_A 3.0 + PROD_Y RES_B 2.0 +RHS + RHS1 RES_A 120.0 + RHS1 RES_B 100.0 +BOUNDS + LO BND1 PROD_X 0.0 + LO BND1 PROD_Y 0.0 +ENDATA diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/model.py new file mode 100644 index 00000000..fb8918c1 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/model.py @@ -0,0 +1,283 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +MPS File Solver using cuOpt Python API + +Read and solve LP/MILP problems from standard MPS files using +cuOpt's built-in readMPS method. + +Default benchmark: air05.mps (airline crew scheduling from MIPLIB) +- Best known optimal: 26,374 +""" + +import os +import gzip +import urllib.request +from typing import Optional + +from cuopt.linear_programming.problem import Problem +from cuopt.linear_programming.solver_settings import SolverSettings + + +# MIPLIB benchmark URL +AIR05_URL = "https://miplib.zib.de/WebData/instances/air05.mps.gz" +AIR05_OPTIMAL = 26374 # Best known optimal solution + + +def download_air05(data_dir: str) -> str: + """Download air05.mps from MIPLIB if not present.""" + mps_file = os.path.join(data_dir, "air05.mps") + + if os.path.exists(mps_file): + return mps_file + + os.makedirs(data_dir, exist_ok=True) + gz_file = os.path.join(data_dir, "air05.mps.gz") + + print("Downloading air05.mps from MIPLIB...") + urllib.request.urlretrieve(AIR05_URL, gz_file) + + # Decompress + print("Decompressing...") + with gzip.open(gz_file, "rb") as f_in: + with open(mps_file, "wb") as f_out: + f_out.write(f_in.read()) + + # Clean up + os.remove(gz_file) + print(f"Downloaded: {mps_file}") + + return mps_file + + +def solve_mps( + filepath: str, + time_limit: float = 60.0, + mip_gap: float = 0.01, + verbose: bool = True, +) -> tuple: + """ + Solve an LP/MILP problem from an MPS file. + + Parameters + ---------- + filepath : str + Path to the MPS file + time_limit : float + Solver time limit in seconds + mip_gap : float + MIP relative gap tolerance + verbose : bool + Print solver output + + Returns + ------- + tuple + (problem, solution_dict) or (problem, None) if no solution + """ + + # Read MPS file directly (static method returns Problem object) + problem = Problem.readMPS(filepath) + + print(f"Loaded MPS file: {filepath}") + print(f"Variables: {problem.NumVariables}") + print(f"Constraints: {problem.NumConstraints}") + print(f"Is MIP: {problem.IsMIP}") + + # Solver settings + settings = SolverSettings() + settings.set_parameter("time_limit", time_limit) + settings.set_parameter("log_to_console", verbose) + settings.set_parameter("mip_relative_gap", mip_gap) + + # Solve + print("\nSolving...") + problem.solve(settings) + + # Extract solution + status = problem.Status.name + print(f"\nStatus: {status}") + + if status in ["Optimal", "FeasibleFound", "PrimalFeasible"]: + solution = { + "status": status, + "objective": problem.ObjValue, + "num_variables": problem.NumVariables, + "num_constraints": problem.NumConstraints, + "is_mip": problem.IsMIP, + "mip_gap": mip_gap, + } + + # Get variable values (use getVariables() for MPS-loaded problems) + var_values = {} + try: + variables = problem.getVariables() + for var in variables: + val = var.getValue() + if abs(val) > 1e-6: # Only include non-zero values + var_values[var.Name] = val + except (AttributeError, Exception): + # For MPS problems, variable access may be limited + pass + + solution["variables"] = var_values + return problem, solution + else: + return problem, None + + +def compare_gaps( + filepath: str, + time_limit: float = 120.0, + known_optimal: Optional[float] = None, +) -> dict: + """ + Compare solutions at different MIP gap tolerances. + + Parameters + ---------- + filepath : str + Path to the MPS file + time_limit : float + Solver time limit per run + known_optimal : float, optional + Known optimal objective value. If provided, results include + "gap_to_optimal" (percent above optimal). Omit for generic MPS files. + + Returns + ------- + dict + Results for each gap tolerance + """ + gaps = [0.01, 0.001] # 1% and 0.1% + results = {} + + for gap in gaps: + print(f"\n{'=' * 60}") + print(f"Solving with MIP gap = {gap * 100}%") + print(f"{'=' * 60}") + + problem, solution = solve_mps( + filepath=filepath, time_limit=time_limit, mip_gap=gap, verbose=True + ) + + if solution: + results[gap] = { + "objective": solution["objective"], + "status": solution["status"], + } + if known_optimal is not None: + results[gap]["gap_to_optimal"] = ( + (solution["objective"] - known_optimal) + / known_optimal + * 100 + ) + else: + results[gap] = {"objective": None, "status": "No solution"} + + return results + + +if __name__ == "__main__": + import argparse + + parser = argparse.ArgumentParser(description="Solve LP/MILP from MPS file") + parser.add_argument( + "--file", type=str, default=None, help="Path to MPS file" + ) + parser.add_argument( + "--time-limit", type=float, default=60.0, help="Solver time limit" + ) + parser.add_argument( + "--mip-gap", type=float, default=0.01, help="MIP gap tolerance" + ) + parser.add_argument( + "--compare", action="store_true", help="Compare 1%% vs 0.1%% gap" + ) + parser.add_argument( + "--known-optimal", + type=float, + default=None, + help="Known optimal objective value (enables gap-to-optimal reporting)", + ) + args = parser.parse_args() + + print("=" * 60) + print("MPS File Solver using cuOpt") + print("=" * 60) + + # Determine MPS file to use + script_dir = os.path.dirname(os.path.abspath(__file__)) + data_dir = os.path.join(script_dir, "data") + + if args.file: + mps_file = args.file + else: + # Download air05.mps if not present + mps_file = download_air05(data_dir) + + # Use known optimal only when explicitly set or when using default air05 + known_optimal = args.known_optimal + if known_optimal is None and mps_file.endswith("air05.mps"): + known_optimal = AIR05_OPTIMAL + + if args.compare: + # Compare different gap tolerances + print(f"\nComparing MIP gap tolerances on: {mps_file}") + if known_optimal is not None: + print(f"Best known optimal: {known_optimal}") + + results = compare_gaps( + mps_file, time_limit=args.time_limit, known_optimal=known_optimal + ) + + print() + print("=" * 60) + print("COMPARISON SUMMARY") + print("=" * 60) + if known_optimal is not None: + print(f"Best known optimal: {known_optimal}") + print() + header = f"{'Gap Tolerance':<15} {'Objective':<15}" + if known_optimal is not None: + header += f" {'Gap to Optimal':<15}" + print(header) + print("-" * (45 if known_optimal is None else 60)) + + for gap, result in sorted(results.items()): + if result["objective"] is not None: + line = f"{gap * 100:.1f}%{'':<12} {result['objective']:<15.0f}" + if known_optimal is not None: + line += f" {result['gap_to_optimal']:.2f}%" + print(line) + else: + print(f"{gap * 100:.1f}%{'':<12} {'No solution':<15}") + else: + # Single solve + print(f"\nMPS File: {mps_file}") + print(f"Time Limit: {args.time_limit}s") + print(f"MIP Gap: {args.mip_gap * 100}%") + print() + + problem, solution = solve_mps( + filepath=mps_file, + time_limit=args.time_limit, + mip_gap=args.mip_gap, + verbose=True, + ) + + if solution: + print() + print("=" * 60) + print("SOLUTION") + print("=" * 60) + print(f"Status: {solution['status']}") + print(f"Objective Value: {solution['objective']:.0f}") + if known_optimal is not None: + print(f"Best Known Optimal: {known_optimal}") + print( + f"Gap to Optimal: {(solution['objective'] - known_optimal) / known_optimal * 100:.2f}%" + ) + else: + print("\nNo feasible solution found.") diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/results.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/results.md new file mode 100644 index 00000000..4100dea6 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/results.md @@ -0,0 +1,90 @@ +# MPS Solver Results + +## Problem: air05.mps (MIPLIB benchmark) + +**Description:** Airline crew scheduling - set partitioning problem + +### Problem Characteristics +- **Variables:** 7195 (all binary) +- **Constraints:** 426 +- **Nonzeros:** 52121 +- **Best Known Optimal:** 26374 + +--- + +## Gap Tolerance Comparison + +Comparing different MIP relative gap tolerances to show trade-off between solution quality and solve time. + +### Run Configuration +- **Time Limit:** 60 seconds +- **cuOpt Version:** 26.2.0 +- **Device:** Quadro RTX 8000 (47.24 GiB VRAM) +- **CPU:** AMD Ryzen Threadripper PRO 3975WX (32 cores) + +### Results Summary + +| Gap Tolerance | Objective | Gap to Optimal | Solve Time | Nodes Explored | +|--------------|-----------|----------------|------------|----------------| +| 0.1% | **26374** | 0.00% | 8.42s | 386 | +| 1.0% | 26491 | 0.44% | 3.23s | 328 | + +### Key Observations + +1. **Tighter gap finds optimal**: The 0.1% gap tolerance found the exact best-known optimal solution (26374) +2. **Trade-off**: The looser 1.0% gap converged faster (3.2s vs 8.4s) but with 0.44% suboptimality +3. **Both are fast**: cuOpt solved this 7195-variable MILP in under 10 seconds + +--- + +## Detailed Solver Output (0.1% gap) + +``` +Solving a problem with 426 constraints, 7195 variables (7195 integers), and 52121 nonzeros + +Presolve removed: 90 constraints, 1116 variables, 16171 nonzeros +Presolved problem: 336 constraints, 6079 variables, 35950 nonzeros + +Root relaxation objective +2.58776093e+04 + +Strong branching using 7 threads and 222 fractional variables +Explored 386 nodes in 7.73s. + +Optimal solution found within relative MIP gap tolerance (1.0e-03) +Solution objective: 26374.000000 +relative_mip_gap 0.000992 +total_solve_time 8.421934 +``` + +--- + +## Detailed Solver Output (1.0% gap) + +``` +Solving a problem with 426 constraints, 7195 variables (7195 integers), and 52121 nonzeros + +Presolve removed: 90 constraints, 1116 variables, 16171 nonzeros +Presolved problem: 336 constraints, 6079 variables, 35950 nonzeros + +Root relaxation objective +2.58776093e+04 + +Strong branching using 63 threads and 222 fractional variables +Explored 328 nodes in 1.09s. + +Optimal solution found within relative MIP gap tolerance (1.0e-02) +Solution objective: 26491.000000 +relative_mip_gap 0.009669 +total_solve_time 3.233650 +``` + +--- + +## Usage + +```bash +# Default: download air05.mps and solve with comparison +python model.py --compare --time-limit 60 + +# Solve custom MPS file +python model.py --file path/to/problem.mps --time-limit 300 --mip-gap 0.001 +``` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/README.md new file mode 100644 index 00000000..cf2173a4 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/README.md @@ -0,0 +1,7 @@ +# Portfolio optimization (QP) + +Minimize portfolio variance (risk) subject to fully invested (sum x = 1) and minimum return. Three assets; Q must be PSD. + +**Run:** `python model.py` + +**Note:** QP is beta; objective must be MINIMIZE. diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/model.py new file mode 100644 index 00000000..0196efdc --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/model.py @@ -0,0 +1,49 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +Portfolio: minimize variance x'Qx subject to sum(x)=1, r'x >= target, x >= 0. +QP is beta; MUST use MINIMIZE. +""" + +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings + +problem = Problem("Portfolio") + +x1 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_a") +x2 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_b") +x3 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_c") + +r1, r2, r3 = 0.12, 0.08, 0.05 +target_return = 0.08 + +problem.setObjective( + 0.04 * x1 * x1 + + 0.02 * x2 * x2 + + 0.01 * x3 * x3 + + 0.02 * x1 * x2 + + 0.01 * x1 * x3 + + 0.016 * x2 * x3, + sense=MINIMIZE, +) +problem.addConstraint(x1 + x2 + x3 == 1, name="budget") +problem.addConstraint( + r1 * x1 + r2 * x2 + r3 * x3 >= target_return, name="min_return" +) + +settings = SolverSettings() +settings.set_parameter("time_limit", 60) +problem.solve(settings) + +if problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"Portfolio variance: {problem.ObjValue:.6f}") + print(f"Std dev: {problem.ObjValue**0.5:.4f}") + print(f" Stock A: {x1.getValue() * 100:.2f}%") + print(f" Stock B: {x2.getValue() * 100:.2f}%") + print(f" Stock C: {x3.getValue() * 100:.2f}%") + print( + f"Expected return: {(r1 * x1.getValue() + r2 * x2.getValue() + r3 * x3.getValue()) * 100:.2f}%" + ) +else: + print(f"Status: {problem.Status.name}") diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/SOURCES.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/SOURCES.md new file mode 100644 index 00000000..f258683e --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/SOURCES.md @@ -0,0 +1,40 @@ +# Sources + +Eval prompts in `evals.json` for the `cuopt-numerical-optimization-api-python` skill are +adapted from the **OptiGuide / OptiMind IndustryOR** dataset: + +- Repository: [microsoft/OptiGuide](https://github.com/microsoft/OptiGuide) +- File: [`optimind/data/optimind_cleaned_classified_industryor.csv`](https://github.com/microsoft/OptiGuide/blob/main/optimind/data/optimind_cleaned_classified_industryor.csv) +- License: MIT (Copyright (c) Microsoft Corporation) + +Each entry's `source` field references the original row index. Problem +statements are quoted verbatim; ground-truth values are the dataset's +optimal objective values. + +## License + +The MIT license under which the source dataset is distributed: + +``` +MIT License + +Copyright (c) Microsoft Corporation. + +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 +``` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/evals.json b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/evals.json new file mode 100644 index 00000000..57ff74c6 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/evals.json @@ -0,0 +1,1091 @@ +[ + { + "id": "lpmilp-001-production-planning-problem", + "question": "A factory produces two types of food, I and II, and currently has 50 skilled workers. It is known that one skilled worker can produce $10 \\ \\mathrm{kg} / \\ \\mathrm{h}$ of food I or $6 \\ \\mathrm{kg} / \\ \\mathrm{h}$ of food II. According to contract bookings, the weekly demand for these two foods will rise sharply, as shown in Table 1-11. Therefore, the factory has decided to train 50 new workers by the end of the 8th week. It is known that a worker works $40 \\ \\mathrm{h}$ per week, and a skilled worker can train up to three new workers in two weeks (during the training period, both the skilled worker and the trainees do not participate in production). The weekly wage of a skilled worker is 360 yuan, the weekly wage of a trainee during the training period is 120 yuan, and after training, the wage is 240 yuan per week, with the same production efficiency as skilled workers. During the transition period of training, many skilled workers are willing to work overtime, and the factory has decided to arrange some workers to work $60 \\ \\mathrm{h}$ per week, with a weekly wage of 540 yuan. If the booked food cannot be delivered on time, the compensation fee for each week of delay per $ \\ \\mathrm{kg}$ is 0.5 yuan for food I and 0.6 yuan for food II. Under these conditions, how should the factory make comprehensive arrangements to minimize the total cost?\n\nTable 1-11\n\n| Week | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |\n|------|---|---|---|---|---|---|---|---|\n| I | 10000 | 10000 | 12000 | 12000 | 16000 | 16000 | 20000 | 20000 |\n| II | 6000 | 7200 | 8400 | 10800 | 10800 | 12000 | 12000 | 12000 |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "219816.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 0 (MIT)" + }, + { + "id": "lpmilp-002-capacitated-lot-sizing-problem-c", + "question": "Each year $t=1,\\dots ,n$ two production lines deliver $a_1=10$ and $a_2=15$ new fighter jets (25 total). $n=10$. Decide how many of that year's 25 aircraft, $x_t$, enter combat immediately and how many, $y_t=25-x_t$, become training platforms. A training jet produces five newly qualified pilots who are available at the start of the next year; every combat jet must be matched with one trained pilot to be operational, and training jets can be reassigned to combat in later years. Starting with no aircraft or pilots, choose integer sequences $\\{x_t,y_t\\}_{t=1}^n$ to maximise the cumulative number of operational combat jet-years $\\sum_{t=1}^{n} x_t$, subject to annual pilot-availability and fleet-balance constraints.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "1350.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 1 (MIT)" + }, + { + "id": "lpmilp-003-capacitated-lot-sizing-problem-c", + "question": "A company specializing in foldable tables needs to create an optimal production and human resources plan for a six-month period (January to June) to maximize its total net profit. The plan must detail monthly in-house production levels, outsourcing quantities, and workforce management (hiring/firing).\n\n**Initial Conditions (at the start of January):**\n- Initial Workforce: 1,000 employees\n- Initial Inventory: 15,000 units\n\n**Revenue and Cost Structure:**\n- **Sales Price:** 300 Yuan per unit sold.\n- **Raw Material Cost:** 90 Yuan per unit, applicable *only* to units produced in-house.\n- **Outsourcing Cost:** 200 Yuan per unit for finished tables acquired from a third-party supplier. This is an all-inclusive cost.\n- **Inventory Holding Cost:** 15 Yuan per unit for any inventory held at the end of a month.\n- **Backorder Cost:** 35 Yuan per unit for any unfulfilled demand (stockout) carried over to the next month.\n\n**Labor and Production Parameters:**\n- **Labor Requirement:** Each in-house unit requires 5 labor hours to produce.\n- **Regular Labor:** Each worker provides 160 regular working hours per month (8 hours/day * 20 days/month). The company pays a regular wage of 30 Yuan/hour for these 160 hours, regardless of full utilization.\n- **Overtime Labor:** Workers can perform overtime. Total overtime hours per month for the entire workforce cannot exceed 20 hours per worker. The overtime wage is 40 Yuan/hour.\n- **Workforce Management:** The company can hire or fire workers each month. The cost to hire a new worker is 5,000 Yuan, and the cost to fire a worker is 8,000 Yuan.\n\n**Demand and Fulfillment Logic:**\n- Unfulfilled demand from one month is back-ordered and must be met in subsequent months.\n- The company fulfills orders (both current demand and backorders) using available inventory from the previous month, current in-house production, and outsourced units.\n\n**Terminal Condition (at the end of June):**\n- The ending inventory must be at least 10,000 units.\n- All backorders must be cleared (i.e., ending backorders must be zero).\n\n**Forecasted Demand:**\n| Month | January | February | March | April | May | June |\n|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n| Demand Forecast | 20,000 | 40,000 | 42,000 | 35,000 | 19,000 | 18,500 |\n\nBased on this information, formulate the optimal six-month operational plan.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "10349920.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 2 (MIT)" + }, + { + "id": "lpmilp-004-farm-planning", + "question": "A farmer needs to decide how many cows, sheep, and chickens to raise in order to achieve maximum profit. The farmer can sell cows, sheep, and chickens for $500, $200, and $8 each, respectively. The feed costs for each cow, sheep, and chicken are $100, $80, and $5, respectively. The profit is the difference between the selling price and the feed cost. Each cow, sheep, and chicken produces 10, 5, and 3 units of manure per day, respectively. Due to the limited time the farm staff has for cleaning the farm each day, they can handle up to 800 units of manure. Additionally, because of the limited farm size, the farmer can raise at most 50 chickens. Furthermore, the farmer must have at least 10 cows to meet customer demand. The farmer must also raise at least 20 sheep. Finally, the total number of animals cannot exceed 100.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "30400.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 3 (MIT)" + }, + { + "id": "lpmilp-005-diet-problem", + "question": "Mary is planning her dinner tonight. Every 100 grams of okra contains 3.2 grams of fiber, every 100 grams of carrots contains 2.7 grams of fiber, every 100 grams of celery contains 1.6 grams of fiber, and every 100 grams of cabbage contains 2 grams of fiber. How many grams of each type of food should Mary buy to maximize her fiber intake?\n\nShe is considering choosing one among salmon, beef, and pork as a protein source. For the chosen protein she must take at least one gram of it.\n\nShe also considers choosing at least two kinds of vegetables among okra, carrots, celery, and cabbage. For each of the selected vegetables, she must take at least one gram.\n\nThe price of salmon is $4 per 100 grams, beef is $3.6 per 100 grams, pork is $1.8 per 100 grams. The price of okra is $2.6 per 100 grams, carrots are $1.2 per 100 grams, celery is $1.6 per 100 grams, and cabbage is $2.3 per 100 grams. Mary has a budget of $15 for this meal.\n\nThe total food intake should be 600 grams.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "18.95657143", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 4 (MIT)" + }, + { + "id": "lpmilp-006-capacitated-lot-sizing-problem-c", + "question": "The contract reservations for the next year for products I, II, and III of a certain factory in each quarter are shown in Table 1-10.\n\nTable 1-10\n| Product | 1 | 2 | 3 | 4 |\n|---------|------|------|------|------|\n| I | 1500 | 1000 | 2000 | 1200 |\n| II | 1500 | 1500 | 1200 | 1500 |\n| III | 1000 | 2000 | 1500 | 2500 |\n\nAt the beginning of the first quarter, there is no inventory for these three products, and it is required to have 150 units in stock for each product by the end of the fourth quarter. It is known that the factory has 15,000 production hours per quarter, and each unit of products I, II, and III requires 2, 4, and 3 hours respectively. Due to a change in equipment, product I cannot be produced in the second quarter. It is stipulated that if the products cannot be delivered on time, a compensation of 20 yuan per unit per quarter delay is required for products I and II, while for product III, the compensation is 10 yuan. Additionally, for products produced but not delivered in the current quarter, the inventory cost is 5 yuan per unit per quarter. How should the factory schedule production to minimize the total cost of compensation and inventory?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "10755.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 5 (MIT)" + }, + { + "id": "lpmilp-007-transportation-problem", + "question": "An Italian transportation company needs to move some empty containers from its 6 warehouses (located in Verona, Perugia, Rome, Pescara, Taranto, and Lamezia) to major national ports (Genoa, Venice, Ancona, Naples, Bari). The container inventory at the warehouses is as follows:\n\n| | Empty Containers |\n|:---:|:---:|\n| Verona | 10 |\n| Perugia | 12 |\n| Rome | 20 |\n| Pescara | 24 |\n| Taranto | 18 |\n| Lamezia | 40 |\n\nThe demand at the ports is as follows:\n\n| | Container Demand |\n|:---:|:---:|\n| Genoa | 20 |\n| Venice | 15 |\n| Ancona | 25 |\n| Naples | 33 |\n| Bari | 21 |\n\nThe transport is carried out by a fleet of trucks. The cost to transport each container is proportional to the distance traveled by the trucks, with a rate of 30 euros per kilometer. Each truck can carry up to 2 containers. The distances are as follows:\n\n| | Genoa | Venice | Ancona | Naples | Bari |\n|:---:|:---:|:---:|:---:|:---:|:---:|\n| Verona | $290 \\mathrm{~km}$ | $115 \\mathrm{~km}$ | $355 \\mathrm{~km}$ | $715 \\mathrm{~km}$ | $810 \\mathrm{~km}$ |\n| Perugia | $380 \\mathrm{~km}$ | $340 \\mathrm{~km}$ | $165 \\mathrm{~km}$ | $380 \\mathrm{~km}$ | $610 \\mathrm{~km}$ |\n| Rome | $505 \\mathrm{~km}$ | $530 \\mathrm{~km}$ | $285 \\mathrm{~km}$ | $220 \\mathrm{~km}$ | $450 \\mathrm{~km}$ |\n| Pescara | $655 \\mathrm{~km}$ | $450 \\mathrm{~km}$ | $155 \\mathrm{~km}$ | $240 \\mathrm{~km}$ | $315 \\mathrm{~km}$ |\n| Taranto | $1010 \\mathrm{~km}$ | $840 \\mathrm{~km}$ | $550 \\mathrm{~km}$ | $305 \\mathrm{~km}$ | $95 \\mathrm{~km}$ |\n| Lamezia | $1072 \\mathrm{~km}$ | $1097 \\mathrm{~km}$ | $747 \\mathrm{~km}$ | $372 \\mathrm{~km}$ | $333 \\mathrm{~km}$ |\n\nWrite a mathematical program to find the minimum cost transportation policy and solve it.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "904590.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 6 (MIT)" + }, + { + "id": "lpmilp-008-assignment-problem", + "question": "Now, we need to determine 4 out of 5 workers to complete one of the four tasks respectively. Due to each worker's different technical specialties, the time required for them to complete each task varies. The hours required by each worker to complete each task are shown in Table 5-2.\n\nTable 5-2\n| Worker | $A$ | $B$ | $C$ | $D$ |\n|--------|-----|-----|-----|-----|\n| I | 9 | 4 | 3 | 7 |\n| II | 4 | 6 | 5 | 6 |\n| III | 5 | 4 | 7 | 5 |\n| IV | 7 | 5 | 2 | 3 |\n| V | 10 | 6 | 7 | 4 |\n\nTry to find a job assignment plan that minimizes the total working hours.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "14.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 7 (MIT)" + }, + { + "id": "lpmilp-009-profit-maximization-problem", + "question": "Haus Toys can manufacture and sell toy trucks, toy airplanes, toy boats, and toy trains. The profit for each truck sold is $5, each airplane $10, each boat $8, and each train $7. How many types of toys should Haus Toys manufacture to maximize profits?\n\nThere are 890 units of wood available. Each truck requires 12 units, each airplane 20 units, each boat 15 units, and each train 10 units.\n\nThere are 500 units of steel available. Each airplane requires 3 units, each boat 5 units, each train 4 units, and each truck 6 units.\n\nIf Haus Toys manufactures trucks, they will not manufacture trains.\n\nHowever, if they manufacture boats, they will also manufacture airplanes.\n\nThe number of toy boats manufactured cannot exceed the number of toy trains manufactured.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "623.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 8 (MIT)" + }, + { + "id": "lpmilp-010-set-cover", + "question": "A convenience supermarket is planning to open several chain stores in a newly built residential area in the northwest suburb of the city. For shopping convenience, the distance from any residential area to one of the chain stores should not exceed $800 \\mathrm{~m}$. Table 5-1 shows the new residential areas and the residential areas within a radius of $800 \\mathrm{~m}$ from each of them. Question: What is the minimum number of chain stores the supermarket needs to build among the mentioned residential areas, and in which residential areas should they be built?\n\n| Area Code | Residential Areas within $800 \\mathrm{~m}$ Radius |\n|-----------|---------------------------------------------------|\n| A | A, C, E, G, H, I |\n| B | B, H, I |\n| C | A, C, G, H, I |\n| D | D, J |\n| E | A, E, G |\n| F | F, J, K |\n| G | A, C, E, G |\n| H | A, B, C, H, I |\n| I | A, B, C, H, I |\n| J | D, F, J, K, L |\n| K | F, J, K, L |\n| L | J, K, L |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "3.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 9 (MIT)" + }, + { + "id": "lpmilp-011-production-planning-problem", + "question": "A company produces two types of small motorcycles, where type A is entirely manufactured by the company, and type B is assembled from imported parts. The production, assembly, and inspection time required for each unit of these two products are shown in Table 3.2.\n\nTable 3.2\n\n| Type | Process | | | Selling Price
(Yuan/unit) |\n| :---: | :---: | :---: | :---: | :---: |\n| | Manufacturing | Assembly | Inspection | |\n| Type A (hours/unit) | 20 | 5 | 3 | 650 |\n| Type B (hours/unit) | 0 | 7 | 6 | 725 |\n| Max production capacity per week (hours) | 120 | 80 | 40 | |\n| Production cost per hour (Yuan) | 12 | 8 | 10 | |\n\nIf the company's operational goals and targets are as follows:\n\n$p_{1}$ : The total profit per week should be at least 3000 yuan;\n\n$p_{2}$ : At least 5 units of type A motorcycles should be produced per week;\n\n$p_{3}$ : Minimize the idle time of each process as much as possible. The weight coefficients of the three processes are their hourly costs, and overtime is not allowed.\n\nTry to establish a model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "272.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 10 (MIT)" + }, + { + "id": "lpmilp-012-facility-location-problem", + "question": "Red Star Plastics Factory produces six distinct types of plastic containers. Each container type is characterized by a specific volume, market demand, and unit variable production cost, as detailed in Table 5-11.\n\n**Table 5-11: Container Data**\n| Container Type (Code) | 1 | 2 | 3 | 4 | 5 | 6 |\n| :------------------------------ | :--- | :--- | :--- | :--- | :--- | :---- |\n| Volume ($\\text{cm}^3$) | 1500 | 2500 | 4000 | 6000 | 9000 | 12000 |\n| Market Demand (units) | 500 | 550 | 700 | 900 | 400 | 300 |\n| Unit Variable Production Cost (Yuan/unit) | 5 | 8 | 10 | 12 | 16 | 18 |\n\nThe production of any container type necessitates the use of its dedicated specialized equipment. If the decision is made to **activate** the production equipment for a particular container type (i.e., if the production quantity of that type is greater than zero), a fixed setup cost of 1200 Yuan is incurred for that specific equipment.\n\nShould the production quantity of a certain container type be insufficient to meet its direct demand, the factory has the option to utilize other container types with **larger or equal volume** as substitutes to fulfill this unmet demand. For instance, type 2 containers (volume 2500 $\\text{cm}^3$) can be used to satisfy the demand for type 1 containers (requiring a volume of 1500 $\\text{cm}^3$), but type 1 containers cannot be used for type 2 demand. In this problem, the container type codes are pre-sorted in ascending order of their volumes.\n\n**Question:**\nHow should the factory organize its production? The objective is to develop a production plan that minimizes the total cost—comprising the sum of variable production costs for all containers produced and the fixed costs for all activated equipment—while ensuring that the demand for all container types is fully met.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "43200.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 11 (MIT)" + }, + { + "id": "lpmilp-013-profit-maximization-problem", + "question": "Tom and Jerry just bought a farm in Sunshine Valley, and they are considering using it to plant corn, wheat, soybeans, and sorghum. The profit per acre for planting corn is $1500, the profit per acre for planting wheat is $1200, the profit per acre for planting soybeans is $1800, and the profit per acre for planting sorghum is $1600. To maximize their profit, how many acres of land should they allocate to each crop? Tom and Jerry’s farm has a total area of 100 acres.\n\nThe land area used for planting corn must be at least twice the land area used for planting wheat.\n\nThe land area used for planting soybeans must be at least half the land area used for planting sorghum.\n\nThe land area used for planting wheat must be three times the land area used for planting sorghum.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "180000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 12 (MIT)" + }, + { + "id": "lpmilp-014-knapsack", + "question": "Mary is planning tonight's dinner. She wants to choose a combination of protein and vegetables to maximize her protein intake for the meal. Her protein options are chicken, salmon, and tofu, which can be bought in any quantity.\n\n- Chicken: 23g protein, $3.00 cost, per 100g.\n- Salmon: 20g protein, $5.00 cost, per 100g.\n- Tofu: 8g protein, $1.50 cost, per 100g.\n\nShe also wants to choose from a list of five vegetables, sold in 100g packs. She must select at least three different types of vegetables.\n\n- Broccoli (100g pack): 2.8g protein, $1.20 cost.\n- Carrots (100g pack): 0.9g protein, $0.80 cost.\n- Spinach (100g pack): 2.9g protein, $1.50 cost.\n- Bell Pepper (100g pack): 1.0g protein, $1.00 cost.\n- Mushrooms (100g pack): 3.1g protein, $2.00 cost.\n\nMary has two main constraints:\n1. Her total budget is $20.\n2. The total weight of all food must not exceed 800 grams.\n\nHow should Mary choose her ingredients to get the maximum possible amount of protein?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "123.8", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 13 (MIT)" + }, + { + "id": "lpmilp-015-lot-sizing-problem", + "question": "A certain factory needs to use a special tool over $n$ planning stages. At stage $j$, $r_j$ specialized tools are needed. At the end of this stage, all tools used within this stage must be sent for repair before they can be reused. There are two repair methods: one is slow repair, which is cheaper (costs $b$ per tool) but takes longer ($p$ stages to return, e.g. if a tool goes to repair after stage 1, it will return at stage 1+p); the other is fast repair, which costs $c$ per tool $(c > b)$ and is faster, requiring only $q$ stages to return $(q < p)$. If the repaired tools cannot meet the needs, new ones must be purchased, with a cost of $a$ per new tool $(a > c)$. This special tool will no longer be used after $n$ stages. Determine an optimal plan for purchasing and repairing the tools to minimize the cost spent on tools during the planning period.\\n\\nn = 10 # number of stages\\nr = [3, 5, 2, 4, 6, 5, 4, 3, 2, 1] # tool requirements per stage, indexing starts at 1\\na = 10 # cost of buying a new tool\\nb = 1 # cost of slow repair\\nc = 3 # cost of fast repair\\np = 3 # slow repair duration\\nq = 1 # fast repair duration", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "134.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 14 (MIT)" + }, + { + "id": "lpmilp-016-lot-sizing-problem", + "question": "A store plans to formulate the purchasing and sales plan for a certain product for the first quarter of next year. It is known that the warehouse capacity of the store can store up to 500 units of the product, and there are 200 units in stock at the end of this year. The store purchases goods once at the beginning of each month. The purchasing and selling prices of the product in each month are shown in Table 1.3.\n\nTable 1.3\n\n| Month | 1 | 2 | 3 |\n| :---: | :---: | :---: | :---: |\n| Purchasing Price (Yuan) | 8 | 6 | 9 |\n| Selling Price (Yuan) | 9 | 8 | 10 |\n\nNow, determine how many units should be purchased and sold each month to maximize the total profit, and express this problem as a linear programming model.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "4100.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 15 (MIT)" + }, + { + "id": "lpmilp-017-production-planning-problem", + "question": "A textile factory produces two types of fabrics: one for clothing and the other for curtains. The factory operates two shifts, with a weekly production time set at 110 hours. Both types of fabrics are produced at a rate of 1000 meters per hour. Assuming that up to 70,000 meters of curtain fabric can be sold per week, with a profit of 2.5 yuan per meter, and up to 45,000 meters of clothing fabric can be sold per week, with a profit of 1.5 yuan per meter, the factory has the following objectives in formulating its production plan:\n\n$p_{1}$ : The weekly production time must fully utilize 110 hours;\n\n$p_{2}$ : Overtime should not exceed 10 hours per week;\n\n$p_{3}$ : At least 70,000 meters of curtain fabric and 45,000 meters of clothing fabric must be sold per week;\n\n$p_{4}$ : Minimize overtime as much as possible.\n\nFormulate a model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "5.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 16 (MIT)" + }, + { + "id": "lpmilp-018-production-planning-problem", + "question": "A furniture store can choose to order chairs from three different manufacturers: A, B, and C. The cost of ordering each chair from manufacturer A is $50, from manufacturer B is $45, and from manufacturer C is $40. The store needs to minimize the total cost of the order.\n\nAdditionally, each order from manufacturer A will include 15 chairs, while each order from manufacturers B and C will include 10 chairs. The number of orders must be an integer. The store needs to order at least 100 chairs.\n\nEach order from manufacturer A will include 15 chairs, while each order from manufacturers B and C will include 10 chairs. The store needs to order at most 500 chairs.\n\nIf the store decides to order chairs from manufacturer A, it must also order at least 10 chairs from manufacturer B.\n\nFurthermore, if the store decides to order chairs from manufacturer B, it must also order chairs from manufacturer C.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "4000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 17 (MIT)" + }, + { + "id": "lpmilp-019-production-planning-problem", + "question": "Bright Future Toys wants to build and sell robots, model cars, building blocks, and dolls. The profit for each robot sold is $15, for each model car sold is $8, for each set of building blocks sold is $12, and for each doll sold is $5. How many types of toys should Bright Future Toys manufacture to maximize profit?\nThere are 1200 units of plastic available. Each robot requires 30 units of plastic, each model car requires 10 units of plastic, each set of building blocks requires 20 units of plastic, and each doll requires 15 units of plastic.\n\nThere are 800 units of electronic components available. Each robot requires 8 units of electronic components, each model car requires 5 units of electronic components, each set of building blocks requires 3 units of electronic components, and each doll requires 2 units of electronic components.\n\nIf Bright Future Toys manufactures robots, they will not manufacture dolls.\n\nHowever, if they manufacture model cars, they will also manufacture building blocks.\n\nThe number of dolls manufactured cannot exceed the number of model cars manufactured.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "956.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 18 (MIT)" + }, + { + "id": "lpmilp-020-lot-sizing-problem", + "question": "A restaurant needs to order dining tables from three different suppliers, A, B, and C. The cost of ordering each dining table from Supplier A is $120, from Supplier B is $110, and from Supplier C is $100. The restaurant needs to minimize the total cost of the order.\n\nAdditionally, each order from Supplier A will include 20 tables, while each order from Suppliers B and C will include 15 tables. The number of orders must be an integer. The restaurant needs to order at least 150 tables.\n\nEach order from Supplier A will include 20 tables, and each order from Suppliers B and C will include 15 tables. The restaurant needs to order no more than 600 tables.\n\nIf the restaurant decides to order tables from Supplier A, it must also order at least 30 tables from Supplier B.\n\nAdditionally, if the restaurant decides to order tables from Supplier B, it must also order tables from Supplier C.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "15000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 19 (MIT)" + }, + { + "id": "lpmilp-021-production-planning-problem", + "question": "A company plans to produce 3 types of products $A_{1}, A_{2}, A_{3}$. It can produce for 22 days in a month. The following table gives the maximum demand (unit $=100 \\mathrm{~kg}$), price ($\\$ / 100 \\mathrm{Kg}$), production cost (per 100Kg product), and production quota (the maximum number of 100kg units that can be produced in one day if all production lines are devoted to this product).\n\n| Product | $A_{1}$ | $A_{2}$ | $A_{3}$ |\n| :---: | :---: | :---: | :---: |\n| Maximum Demand | 5300 | 4500 | 5400 |\n| Selling Price | $124$ | $109$ | $115$ |\n| Production Cost | $73.30$ | $52.90$ | $65.40$ |\n| Production Quota | 500 | 450 | 550 |\n\nThe fixed activation cost of the production line is as follows:\n\n| Product | $A_{1}$ | $A_{2}$ | $A_{3}$ |\n| :---: | :---: | :---: | :---: |\n| Activation Cost | $170000$ | $150000$ | $100000$ |\n\nMinimum production batch:\n\n$$\n\\begin{array}{c|ccc}\nProduct & A_{1} & A_{2} & A_{3} \\\\\n\\hline\nMinimum Batch & 20 & 20 & 16\n\\end{array}\n$$\n\nPlease formulate an operations research model to determine a production plan that maximizes total revenue while accommodating fixed activation costs and minimum production batch constraints.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "270290.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 20 (MIT)" + }, + { + "id": "lpmilp-022-profit-maximization-problem", + "question": "Hongdou Clothing Factory uses three special equipment to produce shirts, short-sleeved shirts, and casual clothes respectively. It is known that the labor, material usage, selling price, and variable cost of each of the above products are as shown in Table 5-10.\n\nTable 5-10\n\n| Product Name | Labor per unit | Material per unit | Selling Price | Variable Cost |\n|--------------|----------------|------------------|---------------|---------------|\n| Shirt | 3 | 4 | 120 | 60 |\n| Short-sleeve | 2 | 3 | 80 | 40 |\n| Casual Cloth | 6 | 6 | 180 | 80 |\n\nIt is known that the available labor per week is 1500 units, the available material is 1600 units, and the weekly fixed costs for the three special equipment for producing shirts, short-sleeved shirts, and casual clothes are 2000, 1500, and 1000 respectively. Design a weekly production plan for the factory to maximize its profit.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "24000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 21 (MIT)" + }, + { + "id": "lpmilp-023-transportation-problem", + "question": "A manufacturing company needs to transport 1800 units of product from the warehouse to three different sales points. The company has four transportation options to choose from: truck, van, motorcycle, and electric vehicle. Since the van and electric vehicle both consume a lot of energy, the company wants to choose only one of these two options. Each trip with a truck generates 100 units of pollution, a van generates 50 units of pollution, a motorcycle generates 10 units of pollution, and an electric vehicle generates 0 units of pollution. The total pollution generated from all trips cannot exceed 2000 units. At least 10 trips must use a truck. Trucks, vans, motorcycles, and electric vehicles can transport 100 units, 80 units, 40 units, and 60 units of product per trip, respectively. The company needs to ensure that the total amount of transported product is at least 1800 units. Return the minimized pollution in units while meeting all constraints.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "1000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 22 (MIT)" + }, + { + "id": "lpmilp-024-portfoliooptimization", + "question": "An investor plans to invest 100,000 yuan, with two investment options to choose from. The first investment guarantees a return of 0.7 yuan for every 1 yuan invested after one year. The second investment guarantees a return of 2 yuan for every 1 yuan invested after two years, but the investment time must be in multiples of two years. In order to maximize the investor's earnings by the end of the third year, how should the investments be made? Formulate this as a linear programming problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "510000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 23 (MIT)" + }, + { + "id": "lpmilp-025-set-multi-cover", + "question": "The number of salespeople required at a 24-hour convenience store in different time periods is as follows: 2:00-6:00 - 10 people, 6:00-10:00 - 15 people, 10:00-14:00 - 25 people, 14:00-18:00 - 20 people, 18:00-22:00 - 18 people, 22:00-2:00 - 12 people. Salespeople start their shifts at 2:00, 6:00, 10:00, 14:00, 18:00, and 22:00, working continuously for 8 hours. Determine the minimum number of salespeople needed to meet the requirements.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "53.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 24 (MIT)" + }, + { + "id": "lpmilp-026-factory-planning-problem", + "question": "A factory produces three types of products: I, II, and III. Each product needs to go through two processing procedures, A and B. The factory has two pieces of equipment that can complete process A, denoted as A1 and A2; it has three pieces of equipment that complete process B, denoted as B1, B2, and B3. Product I can be processed on any equipment for A and B; Product II can be processed on any A equipment but only on B1 for process B; Product III can only be processed on A2 and B2. Given the unit processing time on various machines, raw material costs, product sale prices, effective machine hours, and the costs of operating the machines at full capacity as shown in Table 1-4, the task is to arrange the optimal production plan to maximize the factory's profit.\n\nTable 1-4\n| Equipment | Product I | Product II | Product III | Effective Machine Hours | Operating Costs at Full Capacity (Yuan) |\n|------------|-----------|------------|-------------|--------------------------|------------------------------------------|\n| A1 | 5 | 10 | | 6000 | 300 |\n| A2 | 7 | 9 | 12 | 10000 | 321 |\n| B1 | 6 | 8 | | 4000 | 250 |\n| B2 | 4 | | 11 | 7000 | 783 |\n| B3 | 7 | | | 4000 | 200 |\n| Raw Material Cost (Yuan/Unit) | 0.25 | 0.35 | 0.50 | | |\n| Unit Price (Yuan/Unit) | 1.25 | 2.00 | 2.80 | | |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "1146.4142", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 25 (MIT)" + }, + { + "id": "lpmilp-027-profit-maximization-problem", + "question": "Someone has a fund of 300,000 yuan and has the following investment projects in the next three years:\n(1) Investment can be made at the beginning of each year within three years, with an annual profit of 20% of the investment amount, and the principal and interest can be used for investment in the following year;\n(2) Investment is only allowed at the beginning of the first year, and it can be recovered at the end of the second year, with the total principal and interest amounting to 150% of the investment amount, but the investment limit is no more than 150,000 yuan;\n(3) Investment is allowed at the beginning of the second year within three years, and it can be recovered at the end of the third year, with the total principal and interest amounting to 160% of the investment amount, and the investment limit is 200,000 yuan;\n(4) Investment is allowed at the beginning of the third year within three years, and it can be recovered in one year with a profit of 40%, and the investment limit is 100,000 yuan.\nChapter One: Linear Programming and Simplex Method\nTry to determine an investment plan for this person that maximizes the principal and interest at the end of the third year.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "580000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 26 (MIT)" + }, + { + "id": "lpmilp-028-assignment-problem", + "question": "Jieli Company needs to recruit three types of professionals to work in the two regional branches located in Donghai City and Nanjiang City. The demand for different professionals in these regional branches is shown in Table 4-3. After assessing the situation of the applicants, the company has categorized them into 6 types. Table 4-4 lists the specialties each type of person can handle, the specialty they prefer, and the city they prefer to work in. The company's personnel arrangement considers the following three priorities:\n$p_1$: All three types of professionals needed are fully met;\n$p_2$: 4000 recruited personnel meet their preferred specialty;\n$p_3$: 4000 recruited personnel meet their preferred city.\nFormulate a plan to minimize the total number of people that need to move from one city to another to meet these priorities. Return the minimized objective value.\n\nTable 4-3\n| Branch Location | Specialty | Demand |\n|-----------------|-----------|--------|\n| Donghai City | 1 | 1000 |\n| Donghai City | 2 | 2000 |\n| Donghai City | 3 | 1500 |\n| Nanjiang City | 1 | 2000 |\n| Nanjiang City | 2 | 1000 |\n| Nanjiang City | 3 | 1000 |\n\nTable 4-4\n\n| Type | Number of People | Suitable Specialty | Preferred Specialty | Preferred City |\n|------|------------------|--------------------|---------------------|----------------|\n| 1 | 1500 | 1,2 | 1 | Donghai |\n| 2 | 1500 | 2,3 | 2 | Donghai |\n| 3 | 1500 | 1,3 | 1 | Nanjiang |\n| 4 | 1500 | 1,3 | 3 | Nanjiang |\n| 5 | 1500 | 2,3 | 3 | Donghai |\n| 6 | 1500 | 3 | 3 | Nanjiang |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "2000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 27 (MIT)" + }, + { + "id": "lpmilp-029-diet-problem", + "question": "Suppose a certain animal needs at least $700 \\mathrm{~g}$ of protein, $30 \\mathrm{~g}$ of minerals, and $100 \\mathrm{mg}$ of vitamins daily. There are 5 types of feed available, and the nutritional content and price per kilogram of each type of feed are shown in Table 1-5:\nTry to formulate a linear programming model that meets the animal's growth needs while minimizing the cost of selecting the feed.\nTable 1-6\n| Feed | Protein (g) | Minerals (g) | Vitamins (mg) | Price (¥/kg) | Feed | Protein (g) | Minerals (g) | Vitamins (mg) | Price (¥/kg) |\n|------|-------------|--------------|---------------|--------------|------|-------------|--------------|---------------|--------------|\n| 1 | 3 | 1 | 0.5 | 0.2 | 4 | 6 | 2 | 2 | 0.3 |\n| 2 | 2 | 0.5 | 1 | 0.7 | 5 | 18 | 0.5 | 0.8 | 0.8 |\n| 3 | 1 | 0.2 | 0.2 | 0.4 | | | | | |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "32.43589744", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 28 (MIT)" + }, + { + "id": "lpmilp-030-factory-planning-problem", + "question": "A factory produces three types of products: I, II, and III. Each product must undergo two processing stages, A and B. The factory has two types of equipment to complete stage A (A1, A2) and three types of equipment to complete stage B (B1, B2, B3).\n\nThe production rules are as follows:\n- Product I can be processed on any type of A equipment (A1 or A2) and any type of B equipment (B1, B2, or B3).\n- Product II can be processed on any type of A equipment (A1 or A2), but for stage B, it can only be processed on B1 equipment.\n- Product III can only be processed on A2 equipment for stage A and B2 equipment for stage B.\n\nThe detailed data for processing time per piece, costs, sales price, and machine availability is provided in the table below. The objective is to determine the optimal production plan to maximize the factory's total profit.\n\nData Table\n| Equipment | Product I | Product II | Product III | Effective Machine Hours | Full - load Equipment Cost (Yuan) | Processing Cost per Machine Hour (Yuan/hour) |\n| :--- | :--- | :--- | :--- | :--- | :--- | :--- |\n| A1 | 5 | 10 | - | 6000 | 300 | 0.05 |\n| A2 | 7 | 9 | 12 | 10000 | 321 | 0.03 |\n| B1 | 6 | 8 | - | 4000 | 250 | 0.06 |\n| B2 | 4 | - | 11 | 7000 | 783 | 0.11 |\n| B3 | 7 | - | - | 4000 | 200 | 0.05 |\n| Raw Material Cost (Yuan/piece) | 0.25 | 0.35 | 0.5 | - | - | - |\n| Unit Price (Yuan/piece) | 1.25 | 2 | 2.8 | - | - | - |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "1190.38", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 29 (MIT)" + }, + { + "id": "lpmilp-031-production-planning-problem", + "question": "A product consists of three components produced by four workshops, each with a limited number of production hours. Table 1.4 below provides the production rates of the three components. The objective is to determine the number of hours each workshop should allocate to each component to maximize the number of completed products. Formulate this problem.\n\nTable 1.4\n\n| Workshop | Production Capacity (hours) | Production Rate (units/hour) | | |\n| :------: | :-------------------------: | :--------------------------: | - | - |\n| | | Component 1 | Component 2 | Component 3 |\n| A | 100 | 10 | 15 | 5 |\n| B | 150 | 15 | 10 | 5 |\n| C | 80 | 20 | 5 | 10 |\n| D | 200 | 10 | 15 | 20 |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "2924.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 30 (MIT)" + }, + { + "id": "lpmilp-032-knapsack", + "question": "A wealthy noble passed away, leaving the following inheritance:\n\n- A painting by Caillebotte: $25000\n- A bust of Diocletian: $5000\n- A Yuan dynasty Chinese vase: $20000\n- A 911 Porsche: $40000\n- Three diamonds: each $12000\n- A Louis XV sofa: $3000\n- Two very precious Jack Russell racing dogs: each $3000 (will stipulates they must not be separated)\n- A sculpture from 200 AD: $10000\n- A sailing boat: $15000\n- A Harley Davidson motorcycle: $10000\n- A piece of furniture once belonging to Cavour: $13000,\n\nwhich must be shared between two sons. How to formulate a mathematical program and solve it to minimize the difference in value between the two parts?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "1000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 31 (MIT)" + }, + { + "id": "lpmilp-033-bin-packing", + "question": "The current problem faced by the company is how to use the fewest number of containers to pack the currently needed goods for transportation, while considering the weight of the goods, specific packaging requirements, and inventory limitations. Professional modeling and analysis are needed for a batch of goods’ transportation strategy to ensure maximum utilization of the limited container space.\n\nThe company currently has a batch to be transported, with each container able to hold a maximum of 60 tons of goods and each container used must load at least 18 tons of goods. The goods to be loaded include five types: A, B, C, D, and E, with quantities of 120, 90, 300, 90, and 120 respectively. The weights are 0.5 tons for A, 1 ton for B, 0.4 tons for C, 0.6 tons for D, and 0.65 tons for E. Additionally, to meet specific usage requirements, every time A goods are loaded, at least 1 unit of C must also be loaded, but loading C alone does not require simultaneously loading A; and considering the demand limitation for D goods, each container must load at least 12 units of D.\n\nEstablish an operations research model so that the company can use the fewest number of containers to pack this batch of goods.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "7.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 32 (MIT)" + }, + { + "id": "lpmilp-034-flow-shop-scheduling", + "question": "A fabric dyeing plant has 3 dyeing vats. Each batch of fabric must be dyed in sequence in each vat: first, the second, and third vats. The plant must color five batches of fabric of different sizes. The time required in hours to dye batch $i$ in vat $j$ is given in the following matrix:\n\n$$\n\\left(\\begin{array}{ccc}\n3 & 1 & 1 \\\\\n2 & 1.5 & 1 \\\\\n3 & 1.2 & 1.3 \\\\\n2 & 2 & 2 \\\\\n2.1 & 2 & 3\n\\end{array}\\right)\n$$\n\nSchedule the dyeing operations in the vats to minimize the completion time of the last batch.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "14.1", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 33 (MIT)" + }, + { + "id": "lpmilp-035-capacitated-vehicle-routing-prob", + "question": "The Vehicle Routing Problem (VRP) was first proposed by Dantzig and Ramser in 1959. It is a classic combinatorial optimization problem. The basic VRP can be described as follows: in a certain area, there is a number of customers and a distribution center or depot. Customers are generally located at different positions, and each has a specific demand for goods. The distribution center needs to dispatch a fleet of vehicles and design appropriate delivery routes to fulfill the demands of all customers. The objective of VRP is to optimize a certain benefit metric while satisfying all customer demands. The benefit metric is usually presented as an objective function, which varies according to the company's requirements. Common objective functions include minimizing the total distance traveled by vehicles, minimizing the total delivery time, or minimizing the number of vehicles used. In addition to satisfying customer demands, VRP often needs to consider various other constraints, leading to several variants. For example, if the vehicle's load cannot exceed its maximum capacity, the problem becomes the Capacitated Vehicle Routing Problem (CVRP). If each customer's delivery must be made within a specific time frame, the problem becomes the Vehicle Routing Problem with Time Windows (VRPTW).\n\nThe Vehicle Routing Problem with Time Windows (VRPTW) is a classic variant of the VRP. There are many real-world applications of VRPTW, as customer locations often have service time windows. For instance, some logistics centers need to stock parcels during off-peak hours, and large supermarkets need to replenish goods outside of business hours. Real-time delivery services like food delivery also require strict delivery time windows. Time windows can be categorized as hard or soft. A Hard Time Window (HTW) means that a vehicle must arrive at the delivery point within or before the time window; late arrivals are not permitted. If a vehicle arrives early, it must wait until the time window opens to begin service. This is common in scenarios like supermarket restocking and logistics center inbound operations. A Soft Time Window (STW) means that a vehicle is not strictly required to arrive within the time window, but it is encouraged to do so. A penalty is incurred for early or late arrivals. This is applicable in scenarios such as meal delivery, school bus services, and industrial deliveries.\n\nThe Vehicle Routing Problem with Hard Time Windows (VRPHTW) can be described as follows: within a region, there is a set of customer locations and a central depot. Vehicles must start from the depot and return to the depot, following continuous paths. Each customer must be served by exactly one vehicle, and vehicles have a limited capacity. Each customer has a specific service time window, and service is only accepted within this window. A vehicle can arrive at a customer location early and wait for the time window to open, or it can arrive within the time window to provide service. Service can only begin within the time window, and the service duration is known. The distribution center must arrange an optimal delivery plan to both complete the delivery tasks and minimize travel costs. Because VRPHTW does not allow for delays, it, like the VRP, primarily emphasizes the minimization of travel costs along the routes.\n\n Now we consider a major enterprise logistics provider, 'Global Logistics', is responsible for providing precise material delivery services for multiple high-end office buildings and shops in a city's central business district (CBD). Due to traffic control in the CBD and the specific receiving requirements of the customers, the delivery task is highly challenging.\n\n**Specific Requirements:**\n\n1. **Delivery Task**: There are 20 customers requiring delivery service on the day, and the demands of all customers must be met.\n2. **Vehicle Constraints**: The company can use at most 5 trucks, and the capacity of each truck is 200 units.\n3. **Capacity Constraint**: The total demand of all customers on a single route must not exceed the truck's maximum capacity (200 units).\n4. **Time Window Constraint**: Each customer has a strict 'hard time window.' Service must begin within this specified time window. Early arrivals must wait, and late arrivals are not permitted.\n5. **Service Time**: Due to the complex handover procedures at customer sites, a fixed service time of 90 minutes is required for unloading, handover, and paperwork at each customer location.\n6. **Optimization Objective**: While satisfying all constraints, the company's objective is to **minimize the total distance traveled by all vehicles** to reduce operational costs.\n\n**Data Details:**\n\n* **Central Depot (Depot 0)**:\n * Coordinates: (40, 50)\n * Operating Time Window: [0, 1236] (minutes)\n* **Customer Locations (Customers 1-20)**: The coordinates, demand, service time window, and service duration for each customer are shown in the table below.\n\n| Customer ID | Coordinates (X, Y) | Demand (units) | Time Window (minutes) | Service Duration (minutes) |\n| :--- | :--- | :--- |:--- | :--- |\n| 1 | (45, 68) | 10 | [912, 967] | 90 |\n| 2 | (45, 70) | 30 | [825, 870] | 90 |\n| 3 | (42, 66) | 10 | [65, 146] | 90 |\n| 4 | (42, 68) | 10 | [727, 782] | 90 |\n| 5 | (42, 65) | 10 | [15, 67] | 90 |\n| 6 | (40, 69) | 20 | [621, 702] | 90 |\n| 7 | (40, 66) | 20 | [170, 225] | 90 |\n| 8 | (38, 68) | 20 | [255, 324] | 90 |\n| 9 | (38, 70) | 10 | [534, 605] | 90 |\n| 10 | (35, 66) | 10 | [357, 410] | 90 |\n| 11 | (35, 69) | 10 | [448, 505] | 90 |\n| 12 | (25, 85) | 20 | [652, 721] | 90 |\n| 13 | (22, 75) | 30 | [30, 92] | 90 |\n| 14 | (22, 85) | 10 | [567, 620] | 90 |\n| 15 | (20, 80) | 40 | [384, 429] | 90 |\n| 16 | (20, 85) | 40 | [475, 528] | 90 |\n| 17 | (18, 75) | 20 | [99, 148] | 90 |\n| 18 | (15, 75) | 20 | [179, 254] | 90 |\n| 19 | (15, 80) | 10 | [278, 345] | 90 |\n| 20 | (30, 50) | 10 | [10, 73] | 90 |\n\nNow, please provide an operations research model for this VRPHTW.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "175.37", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 34 (MIT)" + }, + { + "id": "lpmilp-036-production-planning-problem", + "question": "A factory produces two types of microcomputers, A and B. Each type of microcomputer requires the same two production processes. The processing time, profit from sales, and the maximum weekly processing capacity for each type are shown in Table 3.1.\n\nTable 3.1\n\n| Process | Model | | Maximum Weekly Processing Capacity |\n| :---: | :---: | :---: | :---: |\n| | $\\\\mathrm{A}$ | $\\\\mathrm{B}$ | |\n| I (hours / unit) | 4 | 6 | 150 |\n| II (hours / unit) | 3 | 2 | 70 |\n| Profit ($ per unit) | 300 | 450 | |\n\nThe expected values for the factory's operational goals are as follows:\n\n$p_{1}$: The total weekly profit must not be less than $10,000.\n\n$p_{2}$: Due to contractual requirements, at least 10 units of Model A and at least 15 units of Model B must be produced per week.\n\n$p_{3}$: The weekly production time for Process I should be exactly 150 hours, and the production time for Process II should be fully utilized, with potential overtime if necessary.\n\nTry to establish the mathematical programming model for this problem in oder to maximize total profit.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "11250.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 35 (MIT)" + }, + { + "id": "lpmilp-037-flow-shop-scheduling", + "question": "There are three different products to be processed on three machine tools. Each product must first be processed on machine 1, then sequentially on machines 2 and 3. The order of processing the three products on each machine should remain the same. Assuming $t_{ij}$ represents the time to process the $i$-th product on the $j$-th machine, how should the schedule be arranged to minimize the total processing cycle for the three products? The timetable is as follows:\n| Product | Machine 1 | Machine 2 | Machine 3 |\n|---------|-----------|-----------|-----------|\n| Product 1 | 2 | 3 | 1 |\n| Product 2 | 4 | 2 | 3 |\n| Product 3 | 3 | 5 | 2 |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "14.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 36 (MIT)" + }, + { + "id": "lpmilp-038-transportation-airline-industry", + "question": "A company plans to transport goods between the city and the suburb and needs to choose the most environmentally friendly transportation method. The company can choose from the following three methods: motorcycle, small truck, and large truck. Each motorcycle trip produces 40 units of pollution, each small truck trip produces 70 units of pollution, and each large truck trip produces 100 units of pollution. The company's goal is to minimize total pollution.\n\nThe company can only choose two out of these three transportation methods.\n\nDue to certain road restrictions, the number of motorcycle trips cannot exceed 8.\n\nEach motorcycle trip can transport 10 units of products, each small truck trip can transport 20 units of products, and each large truck trip can transport 50 units of products. The company needs to transport at least 300 units of products.\n\nThe total number of trips must be less than or equal to 20.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "600.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 37 (MIT)" + }, + { + "id": "lpmilp-039-production-planning-problem", + "question": "The independent country of Carelland mainly exports four commodities: steel, engines, electronic components, and plastic. Carelland's Minister of Finance (i.e., Minister of Economy) wants to maximize exports and minimize imports. The unit prices of steel, engines, electronics, and plastic on the world market are, in local currency (Klunz), 500, 1500, 300, 1200 respectively. Producing 1 unit of steel requires 0.02 units of engines, 0.01 units of plastic, 250 Klunz of other imported goods, and 6 person-months of labor. Producing 1 unit of engines requires 0.8 units of steel, 0.15 units of electronic components, 0.11 units of plastic, 300 Klunz of imported goods, and 1 person-year. One unit of electronics requires: 0.01 units of steel, 0.01 units of engines, 0.05 units of plastic, 50 Klunz of imported goods, and 6 person-months of labor. One unit of plastic requires: 0.03 units of engines, 0.2 units of steel, 0.05 units of electronic components, 300 Klunz of imported goods, and 2 person-years. Engine production is limited to 650000 units, and plastic production is limited to 60000 units. The total available labor force per year is 830000 person-months. Write a mathematical program to maximize domestic GDP and solve the problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "36288567.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 38 (MIT)" + }, + { + "id": "lpmilp-040-profit-maximization-problem", + "question": "A person has a fund of 500,000 yuan and the following investment projects available in the next three years:\n\n(1) Investment can be made at the beginning of each year within three years, and the annual profit is 20% of the investment amount.\n\n(2) Investment is only allowed at the beginning of the first year, and can be recovered at the end of the second year, with the total principal and interest being 150% of the investment amount. However, this type of investment is limited to no more than 120,000 yuan.\n\n(3) Investment at the beginning of the second year, recoverable at the end of the second year, with the total principal and interest being 160% of the investment amount. This type of investment is limited to 150,000 yuan.\n\n(4) Investment is allowed at the beginning of the third year, recoverable in one year, with a profit of 40%, and the investment limit is 100,000 yuan.\n\nDetermine an investment plan for the person that maximizes the total principal and interest by the end of the third year.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "964640.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 39 (MIT)" + }, + { + "id": "lpmilp-041-production-planning-problem", + "question": "Two steel furnaces at a steel plant each use two methods of steelmaking simultaneously. The first method takes $a=2$ hours per furnace and costs $m=50$ in fuel expenses; the second method takes $b=3$ hours per furnace and costs $n=70$ in fuel expenses. Assuming each furnace produces $k=10$ tons of steel regardless of the method used, and that at least $d=30$ tons of steel must be produced within $c=12$ hours, how should these two methods be allocated to minimize fuel expenses? Formulate this problem as a linear programming model.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "150.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 40 (MIT)" + }, + { + "id": "lpmilp-042-transportation-problem", + "question": "A production base needs to extract raw materials from warehouses A and B every day for production. The required raw materials are: at least 240 pieces of raw material A, at least 80 kg of raw material B, and at least 120 tons of raw material C. It is known that: Each truck from warehouse A can transport back to the production base 4 pieces of raw material A, 2 kg of raw material B, 6 tons of raw material C, with a freight cost of 200 yuan per truck; each truck from warehouse B can transport back to the production base 7 pieces of raw material A, 2 kg of raw material B, 2 tons of raw material C per day, with a freight cost of 160 yuan per truck. Question: In order to meet production needs, how many trucks should be dispatched daily from warehouse A and warehouse B to minimize the total freight cost?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "6800.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 41 (MIT)" + }, + { + "id": "lpmilp-043-capacitated-facility-location-pr", + "question": "Given that there are $m=2$ production points for a certain type of material, where the output at the $i$-th point $(i=1,2)$ is $a_i$, $a_1 = 100$, and $a_2 = 150$. This material is to be shipped to $n=2$ demand points, where the demand at the $j$-th point $(j=1, 2)$ is $b_j$, $b_1 = 80$, and $b_2 = 120$. It is known that $\\sum_i a_i \\geqslant \\sum_j b_j$. It is also known that when shipping from production points to demand points, it must pass through one of the $p=2$ intermediate marshaling stations. If the $k$-th $(k=1, 2)$ intermediate marshaling station is used, a fixed cost $f_k$ is incurred regardless of the transshipment volume, where $f_1 = 10$ and $f_2 = 15$. The $k$-th intermediate marshaling station has a maximum transshipment capacity limitation $q_k$, where $q_1 = 100$ and $q_2 = 100$. Let $c_{i k}$ and $c'_{k j}$ denote the unit transportation cost from $i$ to $k$ and from $k$ to $j$, respectively, where $c_{11}=2$, $c_{12}=3$, $c_{21}=4$, $c_{22}=1$, $c'_{11}=3$, $c'_{12}=2$, $c'_{21}=1$, and $c'_{22}=4$. Try to determine a transportation plan for this material that minimizes the total cost.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "685.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 42 (MIT)" + }, + { + "id": "lpmilp-044-production-planning-problem", + "question": "A factory produces three types of products, A, B, and C. Each unit of product A requires 1 hour for technical preparation, 10 hours of direct labor, and 3 kg of materials. Each unit of product B requires 2 hours for technical preparation, 4 hours of labor, and 2 kg of materials. Each unit of product C requires 1 hour for technical preparation, 5 hours of labor, and 1 kg of materials. The available technical preparation time is 100 hours, labor time is 700 hours, and materials are 400 kg. The company offers larger discounts for bulk purchases, as detailed in Table 1-22. Determine the company's production plan to maximize profit.\nTable 1-22\n| Product A | | Product B | | Product C | |\n|:---------------|:---------:|:---------------|:---------:|:---------------|:---------:|\n| Sales Volume (pieces) | Profit (yuan) | Sales Volume (pieces) | Profit (yuan) | Sales Volume (pieces) | Profit (yuan) |\n| 0 ~ 40 | 10 | 0 ~ 50 | 6 | 0 ~ 100 | 5 |\n| 40 ~ 100 | 9 | 50 ~ 100 | 4 | Above 100 | 4 |\n| 100 ~ 150 | 8 | Above 100 | 3 | | |\n| Above 150 | 7 | | | | |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "712.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 43 (MIT)" + }, + { + "id": "lpmilp-045-assignment-problem", + "question": "A university computer lab hires 4 undergraduates (designated 1, 2, 3, and 4) and 2 graduate students (designated 5 and 6) for duty answering questions. The maximum duty hours from Monday to Friday and the hourly wage for each person are shown in Table 5-9.\n\nTable 5-9\nStudent ID | Wage (CNY/h) | Monday | Tuesday | Wednesday | Thursday | Friday\n1 | 10.0 | 6 | 0 | 6 | 0 | 7\n2 | 10.0 | 0 | 6 | 0 | 6 | 7\n3 | 9.9 | 4 | 8 | 4 | 0 | 5\n4 | 9.8 | 5 | 5 | 6 | 0 | 4\n5 | 10.8 | 4 | 0 | 4 | 8 | 0\n6 | 11.3 | 5 | 6 | 0 | 6 | 3\n\nThe lab operates from 8:00 AM to 10:00 PM, and there must be one and only one student on duty during open hours. It is also required that each undergraduate must work at least 8 hours per week, and each graduate student must work at least 7 hours per week. Additionally, each student can work no more than 2 shifts per week, and no more than 3 students can be scheduled for duty each day.\n\nBased on these conditions, establish a mathematical model to determine the work schedule that satisfies all requirements.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "717.9", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 44 (MIT)" + }, + { + "id": "lpmilp-046-farm-planning", + "question": "A certain farm has 100 hectares of land and 15,000 yuan in funds for production development. The labor force situation on the farm is 3,500 person-days in autumn and winter, and 4,000 person-days in spring and summer. If the labor force itself is not fully utilized, they can work externally, earning 2.1 yuan/person-day in spring and summer and 1.8 yuan/person-day in autumn and winter.\n\nThe farm cultivates three types of crops: soybeans, corn, and wheat, and also raises dairy cows and chickens. Crop cultivation requires no specialized investment, but raising animals involves an investment of 400 yuan per dairy cow and 3 yuan per chicken. Raising dairy cows requires allocating 1.5 hectares of land per cow to grow feed, and involves 100 person-days in autumn and winter, and 50 person-days in spring and summer per cow. The annual net income is 400 yuan per dairy cow. Raising chickens does not use land, requires 0.6 person-days in autumn and winter, and 0.3 person-days in spring and summer per chicken. Annual net income is 2 yuan per chicken. The current chicken coop can accommodate up to 3,000 chickens, and the cow barn can accommodate up to 32 dairy cows. The labor and income requirements for the three types of crops per year are shown in Table 1-9.\n\nTable 1-9\n| Item | Soybean | Corn | Wheat |\n|----------------|---------|------|-------|\n| Person-days (Autumn/Winter) | 20 | 35 | 10 |\n| Person-days (Spring/Summer) | 50 | 75 | 40 |\n| Annual Net Income (Yuan/hectare) | 175 | 300 | 120 |\n\nDetermine the farm's operating plan to maximize annual net income. Please note that workers can only work externally for full days, fractions are not allowed. It is not possible to change the crop and animal raising plans from season to season.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "20241.8", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 45 (MIT)" + }, + { + "id": "lpmilp-047-production-planning-problem", + "question": "A factory produces two models of microcomputers, A and B. Each model requires the same two processes. The processing time, sales profit, and the factory’s maximum weekly processing capacity for each model are shown in Table 3.1.\n\nTable 3.1\n\n| Process | Model | | Maximum Weekly Processing Capacity |\n| :---: | :---: | :---: | :---: |\n| | $A$ | $B$ | |\n| I (hours/unit) | 4 | 6 | 150 |\n| II (hours/unit) | 3 | 2 | 70 |\n| Profit (yuan/unit) | 300 | 450 | |\n\nGiven the factory's business goals:\n\n$p_{1}$: The total weekly profit should not be less than 10,000 yuan;\n\n$p_{2}$: Due to contract requirements, at least 10 units of model A and at least 15 units of model B must be produced each week;\n\n$p_{3}$: The processing time for Process I should be exactly 150 hours per week, and the processing time for Process II should ideally be fully utilized, with potential for appropriate overtime;\n\n$p_{4}$: If products are produced during overtime in Process II, the profit per unit is reduced by 20 yuan for model A and 25 yuan for model B, and the maximum overtime for Process II is 30 hours per week. Formulate the mathematical model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "11250.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 46 (MIT)" + }, + { + "id": "lpmilp-048-lot-sizing-problem", + "question": "A factory must rent warehouse space to cover storage needs over the next four months. The required storage areas are:\nMonth 1: 1500 m²\nMonth 2: 1000 m²\nMonth 3: 2000 m²\nMonth 4: 1200 m²\n\nWarehouse space can be rented via contracts of fixed duration. A contract of length k months (k ? {1, 2, 3, 4}) may start at the beginning of any month t provided it ends no later than Month 4 (i.e., t + k ? 1 ? 4). A contract starting in month t covers months t through t + k ? 1. The rental fee is charged per square meter per month and depends on the contract length as follows:\n1-month contract: 22 yuan per m² per month\n2-month contract: 21 yuan per m² per month\n3-month contract: 20 yuan per m² per month\n4-month contract: 19 yuan per m² per month\n\nAdditional rules and assumptions:\n\nYou may sign any number of contracts.\n\nRented area is divisible (you may rent any nonnegative real number of m²).\n\nSupply is unlimited at the listed rates.\n\nIn each month, the total active rented area must be at least the required area for that month.\n\nYou pay for the entire area specified in each contract for every month it is active, even if some capacity is unused.\n\nYour task is to choose the start times, durations, and areas of contracts to minimize the total rental cost over the four-month horizon while satisfying the monthly area requirements.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "113000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 47 (MIT)" + }, + { + "id": "lpmilp-049-lot-sizing-problem", + "question": "A store has formulated a purchase and sales plan for a certain product from July to December. It is known that the warehouse capacity must not exceed 500 units, with 200 units in stock at the end of June. Thereafter, purchases are made at the beginning of each month. Assume the purchase and selling prices of this product for each month are shown in Table 1-21. How much should be purchased and sold each month to maximize the total revenue?\n\nTable 1-21\n| Month | 7 | 8 | 9 | 10 | 11 | 12 |\n|-------|----|----|----|----|----|----|\n| Buy | 28 | 24 | 25 | 27 | 23 | 23 |\n| Sell | 29 | 24 | 26 | 28 | 22 | 25 |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "9100.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 48 (MIT)" + }, + { + "id": "lpmilp-050-military-personnel-deployment-pr", + "question": "The number of nurses required in each time period over 24 hours at a certain hospital is as follows: 2:00-6:00 - 10 people, 6:00-10:00 - 15 people, 10:00-14:00 - 25 people, 14:00-18:00 - 20 people, 18:00-22:00 - 18 people, 22:00-2:00 - 12 people. Nurses start shifts in 6 batches at 2:00, 6:00, 10:00, 14:00, 18:00, and 22:00 and work continuously for 8 hours. Please determine: If the hospital can hire contract nurses with the same working hours as regular nurses, and if the pay for regular nurses is 10 yuan/hour and for contract nurses is 15 yuan/hour, should the hospital hire contract nurses and if so, how many?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "4240.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 49 (MIT)" + }, + { + "id": "lpmilp-051-set-multi-cover", + "question": "For a certain 24-hour bus service, the number of drivers and crew members required during different time periods each day is shown in Table 1-2:\nTable 1-2\n\\begin{tabular}{|c|c|c||c|c|c|}\n\\hline Shift & Time & Required number & Shift & Time & Required number \\\\\n\\hline 1 & $6: 00 \\sim 10: 00$ & 60 & 4 & $18 ; 00 \\sim 22 ; 00$ & 50 \\\\\n\\hline 2 & $10 ; 00 \\sim 14 ; 00$ & 70 & 5 & $22 ; 00 \\sim 2 ; 00$ & 20 \\\\\n\\hline 3 & $14 ; 00 \\sim 18 ; 00$ & 60 & 6 & $2: 00 \\sim 6 ; 00$ & 30 \\\\\n\\hline\n\\end{tabular}\n\nAssuming that drivers and crew members start their shifts at the beginning of each time period and work continuously for 8 hours, determine the minimum number of drivers and crew members needed for this bus route. Formulate the linear programming model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "150.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 50 (MIT)" + }, + { + "id": "lpmilp-052-knapsack", + "question": "The Zhang family has 6 children: Harry, Hermione, Ron, Fred, George, and Ginny. The cost of taking Harry is $1200, Hermione is $1650, Ron is $750, Fred is $800, George is $800, and Ginny is $1500. Which children should the couple take to minimize the total cost of taking the children? They can take up to four children on the upcoming trip.\n\nGinny is the youngest, so the Zhang family will definitely take her.\n\nIf the couple takes Harry, they will not take Fred because Harry does not get along with him.\n\nIf the couple takes Harry, they will not take George because Harry does not get along with him.\n\nIf they take George, they must also take Fred.\n\nIf they take George, they must also take Hermione.\n\nEven though it will cost them a lot of money, the Zhang family has decided to take at least three children.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "3050.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 51 (MIT)" + }, + { + "id": "lpmilp-053-production-planning-problem", + "question": "Given that a certain factory plans to produce three types of products, I, II, and III, each product needs to be processed on equipment $A, B, C$ as shown in Table 2-3:\n\nTable 2-3\n| Equipment Code | I | II | III | Effective Monthly Equipment Hours |\n|----------------|----|----|-----|----------------------------------|\n| A | 8 | 2 | 10 | 300 |\n| B | 10 | 5 | 8 | 400 |\n| C | 2 | 13 | 10 | 420 |\n| Unit Product Profit (per thousand yuan) | 3 | 2 | 2.9 | |\n\nHow can the equipment capacity be fully utilized to maximize production profit? The quantity of each product must be an integer.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "134.5", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 52 (MIT)" + }, + { + "id": "lpmilp-054-set-multi-cover", + "question": "A master's student in Operations Research at a certain university is required to select two courses in mathematics, two in operations research, and two in computer science from a total of seven courses: Calculus, Operations Research, Data Structures, Management Statistics, Computer Simulation, Computer Programming, and Forecasting. Some courses belong to only one category: Calculus falls under Mathematics, Computer Programming under Computer Science. However, some courses fall under multiple categories: Operations Research can be considered both Operations Research and Mathematics, Data Structures both Computer Science and Mathematics, Management Statistics both Mathematics and Operations Research, Computer Simulation both Computer Science and Operations Research, and Forecasting both Operations Research and Mathematics. Courses that fall under multiple categories can fulfill the requirement of both categories simultaneously. Additionally, some courses have prerequisites: Computer Simulation or Data Structures requires Computer Programming first, Management Statistics requires Calculus first, and Forecasting requires Management Statistics first. The question is: What is the minimum number of courses a master's student must take, and which specific courses, to meet the above requirements?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "4.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 53 (MIT)" + }, + { + "id": "lpmilp-055-lot-sizing-problem", + "question": "A trading company specializes in the wholesale business of certain grains. The company currently has a warehouse with a capacity of 5000 dan. On January 1, the company has 1000 dan of grain in stock and 20,000 yuan in funds. The estimated grain prices for the first quarter are shown in Table 1-8.\n\nTable 1-8\n| Month | Purchase Price (yuan/dan) | Selling Price (yuan/dan) |\n|-------|---------------------------|--------------------------|\n| 1 | 2.85 | 3.10 |\n| 2 | 3.05 | 3.25 |\n| 3 | 2.90 | 2.95 |\n\nThe purchased grains will be delivered in the same month but can only be sold in the next month, and payment is required upon delivery. The company hopes to have an inventory of 2000 dan at the end of the quarter. What purchasing and selling strategy should be adopted to maximize the total profit over the three months?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "-700.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 54 (MIT)" + }, + { + "id": "lpmilp-056-cutting-stock-problem", + "question": "Assuming a paper mill receives three orders for rolls of paper, with length and width requirements as shown in Table 1.2.\n\nTable 1.2\n\n| Order Number | Width (meters) | Length (meters) |\n| :---: | :---: | :---: |\n| 1 | 0.5 | 1000 |\n| 2 | 0.7 | 3000 |\n| 3 | 0.9 | 2000 |\n\nThe mill produces rolls of paper with standard widths of 1 meter and 2 meters. Assuming the length of the rolls is unlimited and can be spliced to reach the required length, how should the rolls be cut to minimize the area of waste?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "600.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 55 (MIT)" + }, + { + "id": "lpmilp-057-farm-planning", + "question": "Vicky and David have just bought a farm in the Yarra Valley, and they are considering using it to grow apples, pears, oranges, and lemons. The profit for growing one acre of apples is $2000, for one acre of pears is $1800, for one acre of oranges is $2200, and for one acre of lemons is $3000. To achieve maximum profit, how many acres of land should they use to grow each type of fruit? Vicky and David have just bought a farm in the Yarra Valley with a total area of 120 acres.\n\nThe land used to grow apples should be at least twice the land used to grow pears.\n\nThe land used to grow apples should be at least three times the land used to grow lemons.\n\nThe land used to grow oranges must be twice the land used to grow lemons if lemons are grown. If no lemons are grown, then we do not have this constraint.\n\nVicky and David are unwilling to grow more than two types of fruit.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "264000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 56 (MIT)" + }, + { + "id": "lpmilp-058-blending-problem", + "question": "A candy factory uses raw materials A, B, and C to process three different brands of candies, A, B, and C. It is known that the content of A, B, and C in each brand of candy, the cost of raw materials, the monthly limit of each raw material, and the unit processing fee and selling price of the three brands of candies are shown in Table 1-7.\n\nTable 1-7\n\n| Item | A | B | C | Raw Material Cost (Yuan/kg) | Monthly Limit (kg) |\n|:----------------|:---------------|:---------------|:---------------|:-----------------------------|:-------------------|\n| A | ? 60% | ? 15% | | 2.00 | 2000 |\n| B | | | | 1.50 | 2500 |\n| C | ? 20% | ? 60% | ? 50% | 1.00 | 1200 |\n| Processing Fee (Yuan/kg) | 0.50 | 0.40 | 0.30 | | |\n| Selling Price (Yuan/kg) | 3.40 | 2.85 | 2.25 | | |\n\nHow many kilograms of each of the three brands of candies should the factory produce each month to maximize the profit?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "6160.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 57 (MIT)" + }, + { + "id": "lpmilp-059-travelingsalesman", + "question": "A traveling salesman must visit 7 customers at 7 different locations, with the (symmetric) distance matrix as follows:\n\n| | 1 | 2 | 3 | 4 | 5 | 6 | 7 |\n| :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |\n| 1 | - | 86 | 49 | 57 | 31 | 69 | 50 |\n| 2 | | - | 68 | 79 | 93 | 24 | 5 |\n| 3 | | | - | 16 | 7 | 72 | 67 |\n| 4 | | | | - | 90 | 69 | 1 |\n| 5 | | | | | - | 86 | 59 |\n| 6 | | | | | | - | 81 |\n\nFormulate a mathematical program to determine the visiting order starting and ending at location 1 to minimize the travel distance.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "153.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 58 (MIT)" + }, + { + "id": "lpmilp-060-capacitated-facility-location-pr", + "question": "A product can be processed on any one of the four devices: A, B, C, or D. The preparation completion costs when each device is enabled, the unit production cost for the product, and the maximum processing capacity of each device are shown in Table 5-7. If 2000 units of the product need to be produced, how can the total cost be minimized? Try to establish a mathematical model.\n\nTable 5-7\n| Device | Prep Completion Cost (Yuan) | Unit Production Cost (Yuan/Unit) | Maximum Processing Capacity (Units) |\n|--------|------------------------------|----------------------------------|------------------------------------|\n| A | 1000 | 20 | 900 |\n| B | 920 | 24 | 1000 |\n| C | 800 | 16 | 1200 |\n| D | 700 | 28 | 1600 |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "37000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 59 (MIT)" + }, + { + "id": "lpmilp-061-knapsack", + "question": "The Zhang family is deciding to invest in several different restaurants. The annual revenue of Restaurant A is $15,000, Restaurant B is $40,000, Restaurant C is $30,000, and Restaurant D is $50,000. They need to decide whether to purchase each restaurant, with each restaurant being able to be purchased only once. Help them decide which restaurants to buy to maximize their annual income.\nThe cost of Restaurant A is 1.6 million, Restaurant B is 2.5 million, Restaurant C is 1.8 million, and Restaurant D is 3 million. The Zhang family's investment budget is 6 million.\n\nIf they purchase Restaurant D, then they cannot purchase Restaurant A.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "90000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 60 (MIT)" + }, + { + "id": "lpmilp-062-transportation-problem", + "question": "A farmer needs to transport 1000 units of fresh produce from the farm to a nearby market. The farmer has three transportation options: a horse, a bicycle, and a handcart. Since both the bicycle and handcart are very physically demanding, the farmer wants to choose only one of these two transportation methods. The horse generates 80 units of pollution per trip, the bicycle generates 0 units of pollution, and the handcart generates 0 units of pollution. The total amount of pollution generated by all trips must not exceed 1000 units. At least 8 trips must be made using the horse. The horse, bicycle, and handcart can carry 55 units, 30 units, and 40 units of produce per trip respectively. The farmer needs to ensure that the total amount of transported produce is at least 1000 units while minimizing the total amount of pollution. What is the minimum amount of pollution that the farmer can achieve?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "640.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 61 (MIT)" + }, + { + "id": "lpmilp-063-knapsack", + "question": "A company needs to decide whether to hire some of the five candidates to join their R&D team. The salary requirements for candidates F, G, H, I, and J are $12,000, $15,000, $18,000, $5,000, and $10,000 respectively. The company wants to minimize the total amount paid to candidates without exceeding the budget.\n\nThe company's budget is $40,000 and they wish to hire a maximum of 4 new employees.\n\nThe skill levels of the candidates are as follows:\nCandidate F: Level 2\nCandidate G: Level 3\nCandidate H: Level 4\nCandidate I: Level 1\nCandidate J: Level 2\n\nThe company needs to ensure that the total skill level of the hired employees is at least 8.\n\nThe project management experience years of each candidate are as follows:\nCandidate F: 1 year\nCandidate G: 2 years\nCandidate H: 2 years\nCandidate I: 5 years\nCandidate J: 4 years\n\nThey hope the total project management experience of the team is at least 8 years.\n\nDue to the similar technical background of candidates G and J, the company can choose at most one of them.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "38000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 62 (MIT)" + }, + { + "id": "lpmilp-064-production-planning-problem", + "question": "A company produces two types of products: microwave ovens and water heaters, which are manufactured in both workshops A and B. It is known that apart from the purchased parts, the production of one microwave oven requires 2 hours of processing in workshop A and 1 hour of assembly in workshop B. The production of one water heater requires 1 hour of processing in workshop A and 3 hours of assembly in workshop B. After production, both products need inspection, sales, and other procedures. The inspection and sales cost for each microwave oven is 30 yuan, and for each water heater is 50 yuan. Workshop A has 250 hours of available production time per month, with each hour costing 80 yuan; workshop B has 150 hours of available production time per month, with each hour costing 20 yuan. It is estimated that an average of 80 microwave ovens and 50 water heaters can be sold per month next year. Based on these actual conditions, the company has established the following monthly plan constraints:\n\n1. Inspection and sales costs should not exceed 5500 yuan per month;\n2. At least 80 microwave ovens should be sold per month;\n3. The production hours of both workshops A and B should be fully utilized, and overtime for workshop A and B are allowed.\n4. Overtime in workshop A should not exceed 20 hours; we do not have upper limit on workshop B's overtime.\n5. At least 50 water heaters should be sold per month.\n\nTry to determine the monthly production plan for the company.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "30500.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 63 (MIT)" + }, + { + "id": "lpmilp-065-production-planning-problem", + "question": "A toy company manufactures three types of tabletop golf toys, each requiring different manufacturing techniques. The high-end type requires 17 hours of manufacturing labor, 8 hours of inspection, and yields a profit of 300 yuan per unit. The mid-range type requires 10 hours of labor, 4 hours of inspection, and yields a profit of 200 yuan per unit. The low-end type requires 2 hours of labor, 2 hours of inspection, and yields a profit of 100 yuan per unit. Available labor hours are 1000, and available inspection hours are 500. Additionally, market forecasts indicate a demand of no more than 50 units for the high-end type, no more than 80 units for the mid-range type, and no more than 150 units for the low-end type. Determine the production plan for the company to maximize profit.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "25000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 64 (MIT)" + }, + { + "id": "lpmilp-066-lot-sizing-problem", + "question": "The market demand for products I and II is as follows: Product I requires 10,000 units per month from January to April, 30,000 units per month from May to September, and 100,000 units per month from October to December. Product II requires 15,000 units per month from March to September and 50,000 units per month during other months. The cost of producing these two products at a certain factory is as follows: Product I costs 5 yuan per unit to produce from January to May, and 4.50 yuan per unit from June to December; Product II costs 8 yuan per unit to produce from January to May, and 7 yuan per unit from June to December. The factory's combined production capacity for both products should not exceed 120,000 units per month. Product I has a volume of 0.2 cubic meters per unit, Product II has a volume of 0.4 cubic meters per unit, and the factory's warehouse capacity is 15,000 cubic meters. If the factory's warehouse space is insufficient, external warehouse space can be rented. Using the factory’s own warehouse costs 1 yuan per cubic meter per month, while renting an external warehouse increases this cost to 1.5 yuan per cubic meter per month. Given that the initial inventory of both products at the beginning of July is zero, how should production be scheduled from July to December to minimize the total production and inventory costs while meeting market demand?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "3160500.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 65 (MIT)" + }, + { + "id": "lpmilp-067-transportation-problem", + "question": "There are two coal yards A and B, each receiving no less than 80 tons and 100 tons of coal per month, respectively. They are responsible for supplying coal to three residential areas, which need 55 tons, 75 tons, and 50 tons of coal per month, respectively. Coal yard A is located 10 kilometers, 5 kilometers, and 6 kilometers from these three residential areas. Coal yard B is located 4 kilometers, 8 kilometers, and 15 kilometers from these three residential areas. How should these two coal yards distribute coal to the three residential areas to minimize the ton-kilometers of transportation?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "1030.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 66 (MIT)" + }, + { + "id": "lpmilp-068-cutting-stock-problem", + "question": "A steel reinforcement workshop produces a batch of steel bars (with the same diameter), consisting of 90 pieces of 3 meters in length and 60 pieces of 4 meters in length. It is known that each piece of raw steel bar used is 10 meters in length. How can the raw material be cut most efficiently? Establish a linear programming model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "53.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 67 (MIT)" + }, + { + "id": "lpmilp-069-travelingsalesman", + "question": "The famous Traveling Salesman Problem (TSP) in operations research can be described as follows: A traveling salesman departs from a certain city, and must visit each city exactly once before returning to the original starting city. The distances between the cities are provided in the table below (the entry at row i and column j represents the cost of going from city i to city j)\n| City | 1 | 2 | 3 | 4 |\n| ---- | ------ | ------ | ------ | ------ |\n| 1 | 0 | 10 | 20 | 12 |\n| 2 | 10 | 0 | 5 | 10 |\n| 3 | 20 | 5 | 0 | 8 |\n| 4 | 15 | 12 | 8 | 0 |\n\nWhat route should the salesman choose to travel in order to minimize the total distance? Try to formulate an integer programming model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "35.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 68 (MIT)" + }, + { + "id": "lpmilp-070-assignment-problem", + "question": "Consider assigning $n=2$ factories to $n$ locations. The transportation volume between factory $i$ and factory $j$ is $d_{ij}$, and the unit transportation cost from location $p$ to location $q$ is $c_{pq}$. The specific values are shown in the following table: Table 1.1\n\n| | Transportation volume to Location 1 | Transportation volume to Location 2 | Transportation cost to Location 1 | Transportation cost to Location 2 |\n| :----: | :---------------------------------: | :---------------------------------: | :-------------------------------: | :-------------------------------: |\n| Factory 1 | 10 | 20 | 5 | 8 |\n| Factory 2 | 30 | 40 | 6 | 7 |\n\nIn order to minimize the total transportation cost, formulate this problem as an integer model.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "330.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 69 (MIT)" + }, + { + "id": "lpmilp-071-knapsack", + "question": "The Li family plans to invest their retirement fund in commercial real estate. The annual income from Property 1 is $12,500, Property 2 is $35,000, Property 3 is $23,000, and Property 4 is $100,000. The decision to be made is whether to buy each property or not, rather than how many to buy, as there is only one of each property available. Help them decide which properties to purchase to maximize their annual income.\n\nThe cost of Property 1 is $1.5 million, Property 2 is $2.1 million, Property 3 is $2.3 million, and Property 4 is $4.2 million. The Li family's budget is $7 million.\n\nIf they purchase Property 4, they cannot purchase Property 3.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "135000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 70 (MIT)" + }, + { + "id": "lpmilp-072-knapsack", + "question": "The Li family has 5 children: Alice, Bob, Charlie, Diana, and Ella. The cost to take Alice is $1000, Bob is $900, Charlie is $600, Diana is $500, and Ella is $700. Which children should the couple take to minimize the total cost of taking the children?\n\nThey can take up to 3 children on the upcoming trip.\n\nBob is the youngest, so the Li family will definitely take him.\n\nIf the couple takes Alice, they will not take Diana because Alice does not get along with her.\n\nIf the couple takes Bob, they will not take Charlie because Bob does not get along with him.\n\nIf they take Charlie, they must also take Diana.\n\nIf they take Diana, they must also take Ella.\n\nDespite the cost, the Li family has decided to take at least two children.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "1600.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 71 (MIT)" + }, + { + "id": "lpmilp-073-operations-optimization", + "question": "A project includes the following 7 activities, with their durations (in days) as follows: $A(4), B(3), C(5), D(2), E(10), F(10), G(1)$. The precedence relationships are also given as: $A \\rightarrow G, D ; E, G \\rightarrow F; D, F \\rightarrow C ; F \\rightarrow B$. The cost of work per day is 1000 Euros; additionally, a special machine must be rented from the start of activity $A$ to the end of activity $B$, costing 5000 Euros per day. Formulate this as a linear programming problem to minimize cost and complete all activities.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "115000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 72 (MIT)" + }, + { + "id": "lpmilp-074-production-planning-problem", + "question": "There are $\\mathrm{A}$ and $\\mathrm{B}$ two products, both requiring two successive chemical reaction processes. Each unit of product $\\mathrm{A}$ needs 2 hours for the first process and 3 hours for the second process. Each unit of product $\\mathrm{B}$ needs 3 hours for the first process and 4 hours for the second process. Available time for the first process is 16 hours, and available time for the second process is 24 hours.\n\nFor each unit of product $\\mathrm{B}$ produced, 2 units of by-product $\\mathrm{C}$ are generated simultaneously, requiring no additional cost. By-product $\\mathrm{C}$ can be sold up to 5 units, and the rest must be disposed of at a cost of 2 yuan per unit.\n\nEach unit of product $\\mathrm{A}$ sold yields a profit of 4 yuan, each unit of product $\\mathrm{B}$ yields a profit of 10 yuan, and each unit of by-product $\\mathrm{C}$ sold yields a profit of 3 yuan.\n\nIn order to maximize total profit, establish the linear programming model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "57.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 73 (MIT)" + }, + { + "id": "lpmilp-075-lot-sizing-problem", + "question": "A timber storage and transport company has a large warehouse for storing and transporting timber for sale. Due to seasonal price fluctuations, the company purchases timber at the beginning of each quarter, with part of it being sold within the quarter and part being stored for future sales. It is known that the maximum storage capacity of the company's warehouse is 200,000 m³, and the storage cost is $(a+b u)$ yuan/m³, where $a=70$, $b=100$, and $u$ is the storage time (in quarters). The purchase and sale prices for each quarter and the estimated maximum sales volumes are shown in Table 1-18.\n\nTable 1-18\n| Quarter | Purchase Price (10,000 yuan/10,000 m²) | Sale Price (10,000 yuan/10,000 m²) | Estimated Maximum Sales Volume (10,000 m³) |\n|---------|----------------------------------------|------------------------------------|---------------------------------------------|\n| Winter | 410 | 425 | 100 |\n| Spring | 430 | 440 | 140 |\n| Summer | 460 | 465 | 200 |\n| Autumn | 450 | 455 | 160 |\n\nSince timber is not suitable for long-term storage, all inventory should be sold by the end of autumn. Try to establish a linear programming model for this problem to maximize the company's annual profit. Return your answer in the unit of 10000 yuan.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "4700.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 74 (MIT)" + }, + { + "id": "lpmilp-076-capacitated-facility-location-pr", + "question": "There are 10 different parts, and they can all be processed on machine \\( A \\), machine \\( B \\), or machine \\( C \\). The unit processing costs are shown in Table 5-6. Additionally, as long as any part is processed on the aforementioned machines, a one-time setup cost will be incurred regardless of whether one or multiple types of parts are processed, with the respective costs being \\( d_A = 100 \\), \\( d_B = 135 \\), and \\( d_C = 200 \\) yuan. If the requirements are:\n\n1. One piece of each of the aforementioned 10 types of parts needs to be processed;\n2. If the 1st part is processed on machine \\( A \\), then the 2nd part must be processed on machine \\( B \\) or \\( C \\); conversely, if the 1st part is processed on machine \\( B \\) or \\( C \\), then the 2nd part must be processed on machine \\( A \\);\n3. Parts 3, 4, and 5 must be processed on machines A, B, and C respectively;\n4. The number of parts processed on machine \\( C \\) should not exceed 3 types.\n\nTry to establish an integer programming mathematical model for this problem with the objective of minimizing the total cost.\n\nTable 5-6\n| Machine/Part | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |\n|--------------|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|\n| A | $10$ | $20$ | $30$ | $40$ | $50$ | $60$ | $70$ | $80$ | $90$ | $100$ |\n| B | $15$ | $25$ | $35$ | $45$ | $55$ | $65$ | $75$ | $85$ | $95$ | $105$ |\n| C | $20$ | $30$ | $40$ | $50$ | $60$ | $70$ | $80$ | $90$ | $100$ | $110$ |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "1005.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 75 (MIT)" + }, + { + "id": "lpmilp-077-operations-optimization", + "question": "A shoe store employs 5 full-time sales clerks and 4 part-time sales clerks. Their working hours and wage conditions are shown in Table 3.3.\n\nTable 3.3\n\n| | Monthly Working Hours | Sales Volume (Pairs/Hour) | Wage (Yuan/Hour) | Overtime Pay (Yuan/Hour) |\n| :---: | :---: | :---: | :---: | :---: |\n| Full-time | 160 | 5 | 1 | 1.5 |\n| Part-time | 80 | 2 | 0.6 | 0.7 |\n\nEach pair of shoes sold earns a profit of 0.3 yuan. The store has set the following goals:\n\n$p_{1}$: Achieve monthly sales of 5500 pairs;\n\n$p_{2}$: Ensure full employment of all sales clerks;\n\n$p_{3}$: Minimize overtime hours.\n\nTry to establish a model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "172.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 76 (MIT)" + }, + { + "id": "lpmilp-078-production-planning-problem", + "question": "A furniture factory needs to decide how many tables, chairs, and bookshelves to produce in order to maximize its profit. The factory can sell each table for $200, each chair for $50, and each bookshelf for $150. The manufacturing costs for each table, chair, and bookshelf are $120, $20, and $90 respectively. The profit is the difference between the selling price and the manufacturing cost. Each table, chair, and bookshelf occupy 5, 2, and 3 square meters of warehouse space respectively. Due to limited warehouse space, the total space cannot exceed 500 square meters. In addition, due to market demand, the factory needs to produce at least 10 tables and 20 bookshelves. Finally, the total number of items produced by the factory cannot exceed 200.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "9800.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 77 (MIT)" + }, + { + "id": "lpmilp-079-operations-optimization", + "question": "A company requires skilled workers and laborers for three tasks. The first task can be completed by one skilled worker alone, or by a group of one skilled worker and two laborers. The second task can be done by one skilled worker or one laborer alone. The third task can be completed by a group of five laborers, or by one skilled worker leading three laborers. The weekly wages for skilled workers and laborers are 100 yuan and 80 yuan respectively. They work 48 hours per week, but their actual effective working hours are 42 hours and 36 hours respectively. To complete these tasks, the company needs a total effective working time of 8400 hours for the first task, 10800 hours for the second task, and 18000 hours for the third task per week. The number of workers that can be recruited is limited to a maximum of 400 skilled workers and 800 laborers. Establish a mathematical model to determine how many skilled workers and laborers should be hired in order to minimize the total wage expenditure.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "84000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 78 (MIT)" + }, + { + "id": "lpmilp-080-assignment-problem", + "question": "On Danzig Street, vehicles can park on both sides of the street. Mr. Edmonds, who lives at No. 1, is organizing a party with about 30 participants, and they will arrive in 15 cars. The length of the i-th car is ?_i, in meters, as follows:\n\n| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |\n|----|----|-----|----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|\n| ?_i | 4 | 4.5 | 5 | 4.1 | 2.4 | 5.2 | 3.7 | 3.5 | 3.2 | 4.5 | 2.3 | 3.3 | 3.8 | 4.6 | 3 |\n\nIn order to avoid disturbing the neighbors, Mr. Edmonds wants to arrange parking on both sides of the street so that the total length of the street occupied by his friends' vehicles is minimized. Please provide a mathematical programming formulation and solve this problem.\nHow does the program change if the cars on one side of the street cannot occupy more than 30 meters?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "28.6", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 79 (MIT)" + }, + { + "id": "lpmilp-081-knapsack", + "question": "Changjiang Comprehensive Shopping Mall has 5000 m² of space for lease and plans to attract the following 5 types of stores as tenants. The table below shows the area occupied by each type of store for one shop, the minimum and maximum number of shops for each type within the mall, and the expected annual profit (in ten thousand yuan) per store for different numbers of stores. Each store pays 20% of its annual profit as rent to the mall. Question: How many of each type of store should the mall lease to maximize total rental income?\n\nTable 5-12\n\n| Code | Store Type | Area per Shop / m² | Min | Max | 1 Store | 2 Stores | 3 Stores |\n|------|------------|--------------------|-----|-----|---------|----------|----------|\n| 1 | Jewelry | 250 | 1 | 3 | 9 | 8 | 7 |\n| 2 | Shoes & Hats | 350 | 1 | 2 | 10 | 9 | - |\n| 3 | General Merchandise | 800 | 1 | 3 | 27 | 21 | 20 |\n| 4 | Bookstore | 400 | 0 | 2 | 16 | 10 | - |\n| 5 | Catering | 500 | 1 | 3 | 17 | 15 | 12 |", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "28.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 80 (MIT)" + }, + { + "id": "lpmilp-082-set-multi-cover", + "question": "A certain restaurant operates around the clock, and the number of waiters needed in 24 hours is shown in Table 1.1.\n\nTable 1.1\n\n| Time | Minimum Number of Waiters Needed | Time | Minimum Number of Waiters Needed |\n|:-----------:|:-------------------------------:|:-----------:|:-------------------------------:|\n| $2 \\sim 6$ | 4 | $14 \\sim 18$| 7 |\n| $6 \\sim 10$ | 8 | $18 \\sim 22$| 12 |\n| $10 \\sim 14$| 10 | $22 \\sim 2$ | 4 |\n\nEach waiter works continuously for 8 hours a day. The goal is to find the minimum number of waiters that meet the above conditions and represent this problem as a linear programming model.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "26.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 81 (MIT)" + }, + { + "id": "lpmilp-083-knapsack", + "question": "A company hopes to recruit new employees for its team. The salary requirements for candidates A, B, C, D, and E are $8100, $20000, $21000, $3000, and $8000 respectively. They need to decide whether to hire each candidate. The team wants to minimize the total amount paid to the candidates.\n\nThey hope to hire a maximum of 3 new employees.\n\nThe team has a limited budget of $35,000. They need to ensure that the total payment to the selected candidates does not exceed the budget.\n\nThe qualifications of the five candidates are as follows:\nCandidate A: Bachelor's degree;\nCandidate B: Master's degree;\nCandidate C: Doctoral degree;\nCandidate D: No degree;\nCandidate E: No degree.\nThey will select at least one candidate with a Master's or Doctoral degree.\n\nThe work experience of the five candidates is as follows:\nCandidate A: 3 years of work experience;\nCandidate B: 10 years of work experience;\nCandidate C: 4 years of work experience;\nCandidate D: 3 years of work experience;\nCandidate E: 7 years of work experience.\nThey hope the total work experience of the selected candidates is no less than 12 years.\n\nDue to the equivalent professional skills of candidates A and E, the company will choose at most one from the two.\n\nThey will hire at least 2 new employees.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "23000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 82 (MIT)" + }, + { + "id": "lpmilp-084-production-planning-problem", + "question": "A company is producing two products (X and Y). The resources required for the production of X and Y are divided into two parts: machine time for automated processing and craftsman time for manual finishing. The table below shows the number of minutes required for each product:\n\n| Item | Machine Time (minutes) | Craftsman Time (minutes) |\n| :---: | :---: | :---: |\n| X | 13 | 20 |\n| Y | 19 | 29 |\n\nThe company has 40 hours of machine time available in the next working week, but only 35 hours of craftsman time. The cost of machine time is £10 per hour, and the cost of craftsman time is £2 per hour. Idle time for machines and craftsmen incurs no cost. For each product produced (all products produced will be sold), the revenue for product X is £20, and the revenue for product Y is £30. Products can only be produced in whole units. The company has a specific contract that requires 10 units of product X to be produced for a customer each week. Formulate a model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "1861.466667", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 83 (MIT)" + }, + { + "id": "lpmilp-085-profit-maximization-problem", + "question": "Healthy Pet Foods Company produces two types of dog food: Meaties and Yummies. Each pack of Meaties contains 2 pounds of grains and 3 pounds of meat; each pack of Yummies contains 3 pounds of grains and 1.5 pounds of meat. The company believes it can sell any quantity of dog food that it can produce. Meaties sell for $2.80 per pack, and Yummies sell for $2.00 per pack. The company's production is subject to several constraints. First, a maximum of 400,000 pounds of grains can be purchased each month at a price of $0.20 per pound of grains. A maximum of 300,000 pounds of meat can be purchased each month at a price of $0.50 per pound of meat. Additionally, a special machine is required to produce Meaties, with a monthly capacity of 90,000 packs. The variable costs for mixing and packaging dog food are $0.25 per pack (Meaties) and $0.20 per pack (Yummies). Detailed information is provided in Table B-1.\n\n**Table B-1 Healthy Pet Foods Data**\n\n| | Meaties | Yummies |\n|--------------------|--------------|------------|\n| Price per pack | $2.80 | $2.00 |\n| Raw materials | | |\n| - Grains | 2.0 lbs | 3.0 lbs |\n| - Meat | 3.0 lbs | 1.5 lbs |\n| Variable cost | $0.25/pack | $0.20/pack |\n| Resources | | |\n| Meaties capacity | 90,000 packs/month | |\n| Monthly available grains | 400,000 lbs | |\n| Monthly available meat | 300,000 lbs | |\n\nAssume you are the manager of the dog food department at Healthy Pet Foods Company. Your salary is based on the department's profit, so you will try to maximize profit. How should you operate the department to maximize both the profit and your salary?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "77500.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 84 (MIT)" + }, + { + "id": "lpmilp-086-multi-commodity-transportation-p", + "question": "A transportation company has two types of trucks, Type A and Type B. Type A trucks have 20 cubic meters of refrigerated capacity and 40 cubic meters of non-refrigerated capacity. In contrast, Type B trucks have the same total capacity, but the capacities for refrigerated and non-refrigerated cargo are equal. A grocer needs to rent trucks to transport 3000 cubic meters of refrigerated cargo and 4000 cubic meters of non-refrigerated cargo. The rental cost per kilometer for Type A trucks is £30, while the rental cost per kilometer for Type B trucks is £40. How many of each type of truck should the grocer rent to minimize the total cost?\n\nTry to formulate a model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "4170.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 85 (MIT)" + }, + { + "id": "lpmilp-087-production-planning-problem", + "question": "A company uses two machines (Machine 1 and Machine 2) to produce two types of products (liquid fertilizer and solid fertilizer). To produce one unit of liquid fertilizer, it takes 50 minutes on Machine 1 and 30 minutes on Machine 2. To produce one unit of solid fertilizer, it takes 24 minutes on Machine 1 and 33 minutes on Machine 2. Fertilizers must be produced in whole units, and fractional amounts are not allowed. At the beginning of the week, there are 30 units of liquid fertilizer and 90 units of solid fertilizer in inventory. The available processing time for Machine 1 this week is expected to be 40 hours, and for Machine 2 it is expected to be 35 hours. The demand for liquid fertilizer this week is estimated at 75 units, and for solid fertilizer at 95 units. The company's policy is to maximize the total number of units of liquid fertilizer and solid fertilizer in inventory at the end of the week.\n\nFormulate a model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "1.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 86 (MIT)" + }, + { + "id": "lpmilp-088-production-planning-problem", + "question": "A company produces product A and product B. Each unit of product A sold generates a profit of £30, while each unit of product B sold generates a profit of £10. The company can allocate a maximum of 40 hours per week for production. Producing one unit of product A requires 6 hours, while producing one unit of product B requires 3 hours, and products can only be produced in whole units. Market demand requires that the quantity of product B produced must be at least three times the quantity of product A. The storage space occupied by product A is four times that of product B. The storage space's capacity is such that it can store 4 units of product A when only product A is stored.\n\nFormulate a model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "140.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 87 (MIT)" + }, + { + "id": "lpmilp-089-revenue-management-problem", + "question": "A store wants to clear out 200 shirts and 100 pairs of pants from last season. They decide to introduce two promotional packages, A and B. Package A includes one shirt and two pairs of pants, priced at £30. Package B includes three shirts and one pair of pants, priced at £50. The store does not want to sell fewer than 20 A packages and 10 B packages. How many of each package do they need to sell to maximize the revenue from the promotion?\n\nTry to establish a model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "3600.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 88 (MIT)" + }, + { + "id": "lpmilp-090-profit-maximization-problem", + "question": "A company produces two products (A and B), with a profit of £3 and £5 per unit sold, respectively. Each product must be assembled on a specific machine, requiring 12 minutes of assembly time per unit for product A and 25 minutes per unit for product B. The company's estimated effective machine working time per week is only 30 hours (due to maintenance or malfunctions). Technical constraints mean that for every five units of product A produced, at least two units of product B must be produced.\n\nTry to formulate a model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "408.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 89 (MIT)" + }, + { + "id": "lpmilp-091-transportation-airline-industry", + "question": "A school is preparing a trip for 400 students. The transportation company has 10 buses with 50 seats each and 8 minibuses with 40 seats each, but only 9 drivers are available. The rental cost for a bus is £800, and the rental cost for a minibus is £600. Calculate how many of each type of bus should be used to achieve the lowest cost.\n\nTry to formulate a model for this problem.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "6200.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 90 (MIT)" + }, + { + "id": "lpmilp-092-production-planning-problem", + "question": "A dairy processing plant uses milk to produce two dairy products, \\( A_{1} \\) and \\( A_{2} \\). One barrel of milk can be processed into 3 kg of \\( A_{1} \\) in 12 hours on Type A equipment or into 4 kg of \\( A_{2} \\) in 8 hours on Type B equipment. According to market demand, all produced \\( A_{1} \\) and \\( A_{2} \\) can be sold. The profit is 24 yuan per kilogram of \\( A_{1} \\) and 16 yuan per kilogram of \\( A_{2} \\). The processing plant can get a daily supply of 50 barrels of milk, with a total of 480 hours of labor time available from regular workers each day. The Type A equipment can process up to 100 kg of \\( A_{1} \\) per day, while the processing capacity of Type B equipment is not limited. Formulate a production plan for the plant to maximize daily profit.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "3360.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 91 (MIT)" + }, + { + "id": "lpmilp-093-blending-problem", + "question": "A company blends two types of crude oil (A and B) to produce two types of gasoline (Type I and Type II). The minimum proportion of crude oil A in gasoline Types I and II is 50% and 60%, respectively. The selling prices are 4800 yuan/t and 5600 yuan/t, respectively. The company has current inventories of 500 t of crude oil A and 1000 t of crude oil B, and they can purchase up to 1500 t of crude oil A from the market. The market price for crude oil A is: 10,000 yuan/t for purchases up to 500 t; 8,000 yuan/t for the portion exceeding 500 t but not exceeding 1000 t; 6,000 yuan/t for the portion exceeding 1000 t. How should the company plan its purchasing and processing of crude oil? Return the maximized profit in yuan.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "5000000.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 92 (MIT)" + }, + { + "id": "lpmilp-094-capacitated-lot-sizing-problem-c", + "question": "A beverage factory produces a kind of beverage to meet market demand. According to market forecasts, the sales department of the factory has determined the demand for the beverage for the next 4 weeks. The planning department, based on the actual situation of the factory, has provided the production capacity and production cost for the next 4 weeks, as shown in Table 1. When there is a surplus of beverages after meeting the demand each week, a storage cost of 0.2 thousand yuan per week per thousand boxes of beverages needs to be paid. How should the production plan be arranged to minimize the total cost (the sum of production cost and storage cost) over the four weeks while meeting the weekly market demand?\n\nTable 1 Beverage Production and Demand Data:\n\n\\begin{tabular}{c|c|c|c}\n\\hline \nWeek & Demand/1000 boxes & Production Capacity/1000 boxes & Cost per 1000 boxes/1000 yuan \\\\\n\\hline \n1 & 15 & 30 & 5.0 \\\\\n\\hline \n2 & 25 & 40 & 5.1 \\\\\n\\hline \n3 & 35 & 45 & 5.4 \\\\\n\\hline \n4 & 25 & 20 & 5.5 \\\\\n\\hline \nTotal & 100 & 135 & \\\\\n\\hline\n\\end{tabular}", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "528.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 93 (MIT)" + }, + { + "id": "lpmilp-095-cutting-stock-problem", + "question": "A steel pipe retailer sources raw steel pipes from a steel pipe factory, cuts the pipes according to customer requirements, and sells them. The raw steel pipes obtained from the factory are all 1850 mm in length. A customer now needs 15 pieces of 290 mm, 28 pieces of 315 mm, 21 pieces of 350 mm, and 30 pieces of 455 mm steel pipes. To simplify the production process, it is required that no more than 4 types of cutting patterns are used. The most frequently used cutting pattern incurs an additional cost of 1/10 of the value of a raw steel pipe, the second most frequent incurs an additional cost of 2/10, and so on. Moreover, the number of cuts for each pattern cannot be too many (a single raw steel pipe can produce up to 5 products). Additionally, to minimize waste, the leftover material for each cutting pattern should not exceed 100 mm. How should the material be cut to minimize total cost, and what is the total cost in this case?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "21.5", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 94 (MIT)" + }, + { + "id": "lpmilp-096-blending-problem", + "question": "A company mixes four types of liquid raw materials with different sulfur contents (denoted as A, B, C, and D, respectively) to produce two products (denoted as \\( \\mathrm{A} \\) and \\( \\mathrm{B} \\)). According to the production process requirements, raw materials A, B, and D must first be mixed in a mixing tank, and then the mixed liquid is further mixed with raw material C to produce \\( \\mathrm{A} \\) and \\( \\mathrm{B} \\). The sulfur contents of raw materials A, B, C, and D are \\( 3\\%, 1\\%, 2\\%, 1\\% \\) respectively, and their purchase prices are 6, 16, 10, 15 (thousand yuan per ton) respectively. The sulfur content of products \\( \\mathrm{A} \\) and \\( \\mathrm{B} \\) must not exceed \\( 2.5\\% \\) and \\( 1.5\\% \\) respectively, and their selling prices are 9, 15 (thousand yuan per ton) respectively. According to market information, there is no limit to the supply of raw materials A, B, and C, but the supply of raw material D is limited to a maximum of 50 tons. The market demand for products \\( \\mathrm{A} \\) and \\( \\mathrm{B} \\) is 100 tons and 200 tons respectively. How should the production be arranged to maximize the total profit?", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "450.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 95 (MIT)" + }, + { + "id": "lpmilp-097-production-planning-problem", + "question": "A company uses steel and aluminum as raw materials to produce two products (A and B). A single unit of product A requires 6 kg of steel, 8 kg of aluminum, 11 hours of labor, and yields a profit of 5000 yuan (excluding worker overtime pay). A single unit of product B requires 12 kg of steel, 20 kg of aluminum, 24 hours of labor, and yields a profit of 11000 yuan (excluding worker overtime pay). Products can only be produced in whole units. The company currently has 200 kg of steel, 300 kg of aluminum, and 300 hours of labor available. If workers need to work overtime, the overtime pay is 100 yuan per hour. Please develop a production plan to maximize the company's overall profit taking into account worker overtime.", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "165900.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 96 (MIT)" + }, + { + "id": "lpmilp-098-knapsack", + "question": "An electronic system is composed of 3 types of components. The system operates normally if all three components function properly. By installing one or more spare parts for any of the components, the reliability of the components can be improved. The system's operational reliability is the product of the reliabilities of each component, and the reliability of each component is a function of the number of spare parts installed. The first half of the table below shows the function relationship between the number of spare parts and the reliability of a specific component. The prices and weights of the 3 types of components are shown in rows 8 to 9 of the table. Given that the total budget for all spare parts is limited to 150 yuan, and the weight limit is 20 kg, how should spare parts be installed to maximize the system's operational reliability? \n\n\\begin{table}[h]\n\\centering\n\\begin{tabular}{|c|c|c|c|}\n\\hline\n\\textbf{Component Number} & \\textbf{1} & \\textbf{2} & \\textbf{3} \\\\ \\hline\n\\textbf{Number of Spares} & & & \\\\ \\hline\n0 & 0.5 & 0.6 & 0.7 \\\\ \\hline\n1 & 0.6 & 0.75 & 0.9 \\\\ \\hline\n2 & 0.7 & 0.95 & 1.0 \\\\ \\hline\n3 & 0.8 & 1.0 & 1.0 \\\\ \\hline\n4 & 0.9 & 1.0 & 1.0 \\\\ \\hline\n5 & 1.0 & 1.0 & 1.0 \\\\ \\hline\n\\textbf{Unit Price (yuan)} & 20 & 30 & 40 \\\\ \\hline\n\\textbf{Unit Weight (kg)} & 2 & 4 & 6 \\\\ \\hline\n\\end{tabular}\n\\caption{Spare Component Data Table}\n\\end{table}", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "0.6075", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 97 (MIT)" + }, + { + "id": "lpmilp-099-network-optimization", + "question": "In network communication services, bandwidth plays an important role. Below is a bandwidth communication table between several communication nodes, showing the bandwidth between any two nodes. If two nodes cannot be directly connected, the corresponding bandwidth is $0$. It is required to establish a link between node $A$ and node $E$ that must pass through service node $C$ (without loops). The bandwidth of this link is defined as the minimum bandwidth value on the link. Please propose a reasonable link arrangement to maximize the bandwidth of this link and find out the maximum bandwidth.\n\n\\begin{table}[h]\n \\centering\n \\begin{tabular}{|c|c|c|c|c|c|}\n \\hline\n & A & B & C & D & E \\\\\n \\hline\n A & 0 & 90 & 85 & 0 & 65 \\\\\n \\hline\n B & 95 & 0 & 70 & 65 & 34 \\\\\n \\hline\n C & 60 & 0 & 0 & 88 & 80 \\\\\n \\hline\n D & 67 & 30 & 25 & 0 & 84 \\\\\n \\hline\n E & 0 & 51 & 0 & 56 & 0 \\\\\n \\hline\n \\end{tabular}\n\\end{table}", + "expected_skill": "cuopt-numerical-optimization-api-python", + "expected_script": null, + "ground_truth": "84.0", + "expected_behavior": [ + "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" + ], + "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 98 (MIT)" + } +] diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/resources/qp_examples.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/resources/qp_examples.md new file mode 100644 index 00000000..80b9802d --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/resources/qp_examples.md @@ -0,0 +1,198 @@ +# QP: Python API Examples + +## Portfolio Optimization + +```python +""" +Minimize portfolio variance (risk): + minimize x^T * Q * x + subject to sum(x) = 1 (fully invested) + r^T * x >= target (minimum return) + x >= 0 (no short selling) + +Note: QP is beta and MUST use MINIMIZE (not MAXIMIZE) +""" +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings + +problem = Problem("Portfolio") + +# Portfolio weights (decision variables) +x1 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_a") +x2 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_b") +x3 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_c") + +# Expected returns +r1, r2, r3 = 0.12, 0.08, 0.05 # 12%, 8%, 5% +target_return = 0.08 + +# Covariance matrix Q: +# [[0.04, 0.01, 0.005], +# [0.01, 0.02, 0.008], +# [0.005, 0.008, 0.01]] +# +# Quadratic objective: x^T * Q * x +# Expanded: 0.04*x1² + 0.02*x2² + 0.01*x3² + 2*0.01*x1*x2 + 2*0.005*x1*x3 + 2*0.008*x2*x3 + +problem.setObjective( + 0.04*x1*x1 + 0.02*x2*x2 + 0.01*x3*x3 + + 0.02*x1*x2 + 0.01*x1*x3 + 0.016*x2*x3, + sense=MINIMIZE # MUST be MINIMIZE for QP! +) + +# Linear constraints +problem.addConstraint(x1 + x2 + x3 == 1, name="budget") +problem.addConstraint(r1*x1 + r2*x2 + r3*x3 >= target_return, name="min_return") + +# Solve +settings = SolverSettings() +settings.set_parameter("time_limit", 60) +problem.solve(settings) + +# Results +if problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"Portfolio variance: {problem.ObjValue:.6f}") + print(f"Portfolio std dev: {problem.ObjValue**0.5:.4f}") + print(f"\nAllocation:") + print(f" Stock A: {x1.getValue()*100:.2f}%") + print(f" Stock B: {x2.getValue()*100:.2f}%") + print(f" Stock C: {x3.getValue()*100:.2f}%") + + actual_return = r1*x1.getValue() + r2*x2.getValue() + r3*x3.getValue() + print(f"\nExpected return: {actual_return*100:.2f}%") +``` + +## Least Squares + +```python +""" +Minimize ||Ax - b||² = (Ax-b)^T(Ax-b) + +Example: Find point closest to (3, 4) +minimize (x-3)² + (y-4)² = x² - 6x + 9 + y² - 8y + 16 +""" +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE +from cuopt.linear_programming.solver_settings import SolverSettings + +problem = Problem("LeastSquares") + +x = problem.addVariable(lb=-100, ub=100, vtype=CONTINUOUS, name="x") +y = problem.addVariable(lb=-100, ub=100, vtype=CONTINUOUS, name="y") + +# Quadratic objective: (x-3)² + (y-4)² +# Expanded: x² + y² - 6x - 8y + 25 +problem.setObjective( + x*x + y*y - 6*x - 8*y + 25, + sense=MINIMIZE +) + +result = problem.solve(SolverSettings()) + +if problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"x = {x.getValue():.4f}") # Should be ~3 + print(f"y = {y.getValue():.4f}") # Should be ~4 +else: + raise RuntimeError(f"Solver failed with status: {problem.Status.name}") +``` + +## Quadratic with Linear Constraints + +```python +""" +minimize x² + y² + z² +subject to x + y + z = 10 + x >= 0, y >= 0, z >= 0 +""" +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE + +problem = Problem("QuadraticConstrained") + +x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") +y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y") +z = problem.addVariable(lb=0, vtype=CONTINUOUS, name="z") + +problem.setObjective(x*x + y*y + z*z, sense=MINIMIZE) +problem.addConstraint(x + y + z == 10) + +problem.solve() + +if problem.Status.name == "Optimal": + print(f"x = {x.getValue():.4f}") + print(f"y = {y.getValue():.4f}") + print(f"z = {z.getValue():.4f}") + print(f"Objective = {problem.ObjValue:.4f}") +``` + +## Maximization Workaround + +```python +""" +QP only supports MINIMIZE. +To maximize f(x), minimize -f(x). + +Example: maximize -x² + 4x (parabola with max at x=2) +""" +from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE + +problem = Problem("MaxWorkaround") + +x = problem.addVariable(lb=0, ub=10, vtype=CONTINUOUS, name="x") + +# Want to maximize: -x² + 4x +# Instead minimize: -(-x² + 4x) = x² - 4x +problem.setObjective(x*x - 4*x, sense=MINIMIZE) + +problem.solve() + +if problem.Status.name in ["Optimal", "PrimalFeasible"]: + print(f"x = {x.getValue():.4f}") # Should be 2 + print(f"Minimized value = {problem.ObjValue:.4f}") # Should be -4 + print(f"Original maximum = {-problem.ObjValue:.4f}") # Should be 4 +else: + print(f"Solver did not find optimal solution. Status: {problem.Status.name}") +``` + +## Expanding Covariance Matrix + +Given covariance matrix Q and weight vector x: + +```python +# Covariance matrix +Q = [ + [0.04, 0.01, 0.005], + [0.01, 0.02, 0.008], + [0.005, 0.008, 0.01] +] + +# Expansion: x^T * Q * x +# = Q[0,0]*x1² + Q[1,1]*x2² + Q[2,2]*x3² +# + 2*Q[0,1]*x1*x2 + 2*Q[0,2]*x1*x3 + 2*Q[1,2]*x2*x3 +# +# = 0.04*x1*x1 + 0.02*x2*x2 + 0.01*x3*x3 +# + 0.02*x1*x2 + 0.01*x1*x3 + 0.016*x2*x3 + +objective = ( + Q[0][0]*x1*x1 + Q[1][1]*x2*x2 + Q[2][2]*x3*x3 + + 2*Q[0][1]*x1*x2 + 2*Q[0][2]*x1*x3 + 2*Q[1][2]*x2*x3 +) +``` + +## Critical Reminders + +1. **MINIMIZE only** - solver rejects MAXIMIZE for QP +2. **Convexity** - Q should be positive semi-definite +3. **Beta status** - API may change in future versions +4. **Status checking** - use PascalCase: `"Optimal"` not `"OPTIMAL"` + +--- + +## Additional References (tested in CI) + +For more complete examples, read these files: + +| Example | File | Description | +|---------|------|-------------| +| Simple QP | `docs/cuopt/source/cuopt-python/lp-qp-milp/examples/simple_qp_example.py` | Basic QP setup | +| QP with Matrix | `docs/cuopt/source/cuopt-python/lp-qp-milp/examples/qp_matrix_example.py` | CSR matrix format for Q | + +These examples are tested by CI (`ci/test_doc_examples.sh`) and represent canonical usage. diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started b/plugins/nvidia-skills/skills/nemoclaw-user-get-started deleted file mode 120000 index 6b780fc1..00000000 --- a/plugins/nvidia-skills/skills/nemoclaw-user-get-started +++ /dev/null @@ -1 +0,0 @@ -../../../skills/NemoClaw/nemoclaw-user-get-started \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/SKILL.md b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/SKILL.md new file mode 100644 index 00000000..5b8c8c95 --- /dev/null +++ b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/SKILL.md @@ -0,0 +1,353 @@ +--- +name: "nemoclaw-user-get-started" +description: "Installs NemoClaw, launches a sandbox, and runs the first agent prompt. Use when onboarding, installing, or launching a NemoClaw sandbox for the first time. Trigger keywords - nemoclaw quickstart, install nemoclaw openclaw sandbox, nemohermes quickstart, hermes agent nemoclaw, run hermes openshell sandbox, nemoclaw prerequisites, nemoclaw supported platforms, nemoclaw hardware software, nemoclaw windows wsl2 setup, nemoclaw install windows docker desktop." +--- + + + + +# NemoClaw Quickstart with OpenClaw + +Follow these steps to get started with NemoClaw and your first sandboxed OpenClaw agent. + +**Note:** + +Make sure you have completed reviewing the Prerequisites (use the `nemoclaw-user-get-started` skill) before following this guide. + +## Install NemoClaw and Onboard OpenClaw Agent + +Download and run the installer script. +The script installs Node.js if it is not already present, then runs the guided onboard wizard to create a sandbox, configure inference, and apply security policies. + +**Note:** + +NemoClaw creates a fresh OpenClaw instance inside the sandbox during the onboarding process. + +```bash +curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +The piped installer prompts through your terminal. In headless scripts or CI, +pass explicit acceptance to the `bash` side of the pipe: + +```console +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | NEMOCLAW_NON_INTERACTIVE=1 NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 bash +``` + +If you use nvm or fnm to manage Node.js, the installer might not update your current shell's PATH. +If `nemoclaw` is not found after install, run `source ~/.bashrc` (or `source ~/.zshrc` for zsh) or open a new terminal. + +On Linux, the installer checks Docker before it installs NemoClaw. +If Docker is missing, the installer downloads the official Docker convenience script, asks for `sudo`, installs Docker, and starts the Docker service when systemd is available. +If Docker is installed but your current shell cannot use the Docker socket yet, the installer adds your user to the `docker` group when needed and exits with a recovery command. + +On macOS, the installer uses the Docker-driver OpenShell gateway path with Docker Desktop or Colima. + +```console +$ newgrp docker +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +On DGX Spark, DGX Station, and Windows WSL, an interactive installer offers express install after you accept the third-party software notice. +Express install switches onboarding to non-interactive mode, allows `sudo` password prompts for required host changes, applies the suggested security policy, and selects the managed local inference path for that platform. +On WSL, express install selects the Windows-host Ollama setup path. +Set `NEMOCLAW_NO_EXPRESS=1` to skip the express prompt, or set `NEMOCLAW_PROVIDER` before launching the installer when you want to choose a provider yourself. + +The installer auto-launches `nemoclaw onboard` when it can locate the freshly-installed binary. +If it cannot locate the binary, or if blocking host preflight checks fail, it does not launch the wizard automatically. +In that case, the installer prints the relevant diagnostics and a `To finish setup, run:` block with the explicit `nemoclaw onboard` command. + +**Note:** + +The onboard flow builds the sandbox image with `NEMOCLAW_DISABLE_DEVICE_AUTH=1` so the dashboard is immediately usable during setup. +This is a build-time setting baked into the sandbox image, not a runtime knob. +If you export `NEMOCLAW_DISABLE_DEVICE_AUTH` after onboarding finishes, it has no effect on an existing sandbox. + +### Respond to the Onboard Wizard + +After the installer launches `nemoclaw onboard`, the wizard runs preflight checks, starts or reuses the OpenShell gateway, and asks for an inference provider, sandbox name, optional web search, optional messaging channels, and network policy presets. +At any prompt, press Enter to accept the default shown in `[brackets]`, type `back` to return to the previous prompt, or type `exit` to quit. +If existing sandbox sessions are running, the installer warns before onboarding because the setup can rebuild or upgrade sandboxes after the new sandbox launches. + +The inference provider prompt presents a numbered list. + +```text + 1) NVIDIA Endpoints + 2) OpenAI + 3) Other OpenAI-compatible endpoint + 4) Anthropic + 5) Other Anthropic-compatible endpoint + 6) Google Gemini + 7) Local Ollama (localhost:11434) + 8) Model Router (experimental) + Choose [1]: +``` + +Pick the option that matches where you want inference traffic to go, then expand the matching helper below for the follow-up prompts and the API key environment variable to set. +For the full list of providers and validation behavior, refer to Inference Options (use the `nemoclaw-user-configure-inference` skill). +Local Ollama appears when NemoClaw detects a usable local Ollama path or can offer an install or start action for your platform. +The Model Router option appears when the blueprint router profile is enabled. + +**Tip:** + +Export the API key before launching the installer so the wizard does not have to ask for it. +For example, run `export NVIDIA_API_KEY=` before `curl ... | bash`. +If you entered a key incorrectly, refer to Reset a Stored Credential (use the `nemoclaw-user-manage-sandboxes` skill) to clear and re-enter it. + +**Option 1: NVIDIA Endpoints:** + +Routes inference to models hosted on [build.nvidia.com](https://build.nvidia.com). + +Use `NVIDIA_API_KEY` for the API key. Get one from the [NVIDIA build API keys page](https://build.nvidia.com/settings/api-keys). + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, press Enter (or type `1`) to select **NVIDIA Endpoints**. +2. At the `NVIDIA_API_KEY:` prompt, paste your key if it is not already exported. +3. At the `Choose model [1]:` prompt, pick a curated model from the list (for example, `Nemotron 3 Super 120B`, `GLM-5`, `MiniMax M2.7`, `GPT-OSS 120B`, or `DeepSeek V4 Pro`), or pick `Other...` to enter any model ID from the [NVIDIA Endpoints catalog](https://build.nvidia.com). + +NemoClaw validates the model against the catalog API before creating the sandbox. + +**Tip:** + +Use this option for Nemotron and other models hosted on `build.nvidia.com`. If you run NVIDIA Nemotron from a self-hosted NIM, an enterprise gateway, or any other endpoint, choose **Option 3** instead, since all Nemotron models expose OpenAI-compatible APIs. + +**Option 2: OpenAI:** + +Routes inference to the OpenAI API at `https://api.openai.com/v1`. + +Use `OPENAI_API_KEY` for the API key. Get one from the [OpenAI API keys page](https://platform.openai.com/api-keys). + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `2` to select **OpenAI**. +2. At the `OPENAI_API_KEY:` prompt, paste your key if it is not already exported. +3. At the `Choose model [1]:` prompt, pick a curated model (for example, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`, or `gpt-5.4-pro-2026-03-05`), or pick **Other...** to enter any OpenAI model ID. + +**Option 3: Other OpenAI-Compatible Endpoint:** + +Routes inference to any server that implements `/v1/chat/completions`, including OpenRouter, LocalAI, llama.cpp, vLLM behind a proxy, and any compatible gateway. + +Use `COMPATIBLE_API_KEY` for the API key. Set it to whatever credential your endpoint expects. If your endpoint does not require auth, use any non-empty placeholder. + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `3` to select **Other OpenAI-compatible endpoint**. +2. At the `OpenAI-compatible base URL` prompt, enter the provider's base URL. Find the exact value in your provider's API documentation. NemoClaw appends `/v1` automatically, so leave that suffix off. +3. At the `COMPATIBLE_API_KEY:` prompt, paste your key if it is not already exported. +4. At the `Other OpenAI-compatible endpoint model []:` prompt, enter the model ID exactly as it appears in your provider's model catalog. + +For example, when you use NVIDIA's OpenAI-compatible inference endpoint, enter `https://inference-api.nvidia.com` as the base URL and the model ID your endpoint exposes, such as `openai/openai/gpt-5.5`. + +NemoClaw sends a real inference request to validate the endpoint and model. +If the endpoint does not return the streaming events OpenClaw needs from the Responses API, NemoClaw falls back to the chat completions API and configures OpenClaw to use `openai-completions`. + +**Tip:** + +NVIDIA Nemotron models expose OpenAI-compatible APIs, so this option is the right choice for any Nemotron deployment that does not live on `build.nvidia.com`. Common examples include a self-hosted NIM container, an enterprise NVIDIA AI Enterprise gateway, or a vLLM/SGLang server running Nemotron weights. Point the base URL at your endpoint and enter the Nemotron model ID exactly as your server reports it. + +**Option 4: Anthropic:** + +Routes inference to the Anthropic Messages API at `https://api.anthropic.com`. + +Use `ANTHROPIC_API_KEY` for the API key. Get one from the [Anthropic console keys page](https://console.anthropic.com/settings/keys). + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `4` to select **Anthropic**. +2. At the `ANTHROPIC_API_KEY:` prompt, paste your key if it is not already exported. +3. At the `Choose model [1]:` prompt, pick a curated model (for example, `claude-sonnet-4-6`, `claude-haiku-4-5`, or `claude-opus-4-6`), or pick **Other...** to enter any Claude model ID. + +**Option 5: Other Anthropic-Compatible Endpoint:** + +Routes inference to any server that implements the Anthropic Messages API at `/v1/messages`, including Claude proxies, Bedrock-compatible gateways, and self-hosted Anthropic-compatible servers. + +Use `COMPATIBLE_ANTHROPIC_API_KEY` for the API key. Set it to whatever credential your endpoint expects. + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `5` to select **Other Anthropic-compatible endpoint**. +2. At the `Anthropic-compatible base URL` prompt, enter the proxy or gateway's base URL from its documentation. +3. At the `COMPATIBLE_ANTHROPIC_API_KEY:` prompt, paste your key if it is not already exported. +4. At the `Other Anthropic-compatible endpoint model []:` prompt, enter the model ID exactly as it appears in your gateway's model catalog. + +**Option 6: Google Gemini:** + +Routes inference to Google's OpenAI-compatible Gemini endpoint at `https://generativelanguage.googleapis.com/v1beta/openai/`. + +Use `GEMINI_API_KEY` for the API key. Get one from [Google AI Studio API keys](https://aistudio.google.com/app/apikey). + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `6` to select **Google Gemini**. +2. At the `GEMINI_API_KEY:` prompt, paste your key if it is not already exported. +3. At the `Choose model [5]:` prompt, pick a curated model (for example, `gemini-3.1-pro-preview`, `gemini-3.1-flash-lite-preview`, `gemini-3-flash-preview`, `gemini-2.5-pro`, `gemini-2.5-flash`, or `gemini-2.5-flash-lite`), or pick **Other...** to enter any Gemini model ID. + +**Option 7: Local Ollama:** + +Routes inference to a local Ollama instance. Depending on your platform, the wizard can use an existing daemon, start an installed daemon, or offer an install action. + +No API key is required. On non-WSL hosts, NemoClaw generates a token and starts an authenticated proxy so containers can reach Ollama without exposing the daemon directly to your network. +On WSL, NemoClaw can also use Ollama on the Windows host through `host.docker.internal`. + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `7` to select **Local Ollama**. +2. At the `Choose model [1]:` prompt, pick from **Ollama models** if any are already installed. If none are installed, pick a **starter model** to pull and load now, or pick **Other...** to enter any Ollama model ID. + +For setup details, including GPU recommendations and starter model choices, refer to Use a Local Inference Server (use the `nemoclaw-user-configure-inference` skill). + +**Option 8: Model Router:** + +Starts a host-side model router and routes sandbox inference through OpenShell to that router. +The router chooses from the model pool in `nemoclaw-blueprint/router/pool-config.yaml` for each request. + +Use `NVIDIA_API_KEY` for the model pool credentials. + +Respond to the wizard as follows. + +1. At the `Choose [1]:` prompt, type `8` to select **Model Router (experimental)**. +2. At the `NVIDIA_API_KEY:` prompt, paste your key if it is not already exported. +3. Review the configuration summary and continue with the sandbox build. + +For scripted setup, set: + +```console +$ NEMOCLAW_PROVIDER=routed NVIDIA_API_KEY= nemoclaw onboard --non-interactive +``` + +The router listens on the host at port `4000`. +The sandbox still calls `https://inference.local/v1`, so do not point in-sandbox tools at the host router port directly. + +**Local NIM and Local vLLM:** + +- **Local NVIDIA NIM** appears when `NEMOCLAW_EXPERIMENTAL=1` is set and the host has a NIM-capable GPU. NemoClaw pulls and manages a NIM container. +- **Local vLLM (already running)** appears whenever NemoClaw detects a vLLM server on `localhost:8000`. No flag is required for the menu entry. NemoClaw auto-detects the loaded model. +- **Local vLLM (managed install/start)** appears by default on DGX Spark and DGX Station. Generic Linux NVIDIA GPU hosts require `NEMOCLAW_EXPERIMENTAL=1` or `NEMOCLAW_PROVIDER=install-vllm`. NemoClaw pulls and starts a vLLM container on supported hosts. + +For setup, refer to Use a Local Inference Server (use the `nemoclaw-user-configure-inference` skill). + +### Review the Configuration Before the Sandbox Build + +After you enter the sandbox name, the wizard prints a review summary and asks for final confirmation before registering the provider, prompting for optional integrations, and building the sandbox image. +For example, if you picked an OpenAI-compatible endpoint, the summary looks like the following: + +```text + ────────────────────────────────────────────────── + Review configuration + ────────────────────────────────────────────────── + Provider: compatible-endpoint + Model: openai/openai/gpt-5.5 + API key: COMPATIBLE_API_KEY (staged for OpenShell gateway registration) + Web search: disabled + Messaging: none + Sandbox name: my-gpt-claw + Note: Sandbox build typically takes 5–15 minutes on this host. + ────────────────────────────────────────────────── + Web search and messaging channels will be prompted next. + Apply this configuration? [Y/n]: +``` + +The default is `Y`, so you can press Enter once to continue. Answer `n` to abort cleanly, fix the entries, and re-run `nemoclaw onboard`. + +Non-interactive runs (`NEMOCLAW_NON_INTERACTIVE=1`) print the summary for log clarity but skip the prompt. + +### Configure Web Search and Messaging + +After you confirm the summary, NemoClaw registers the selected provider with the OpenShell gateway and sets the `inference.local` route. +The wizard then asks whether to enable Brave Web Search. +If you enable it, enter a Brave Search API key when prompted. + +The wizard also offers messaging channels such as Telegram, Discord, Slack, and WhatsApp. +Press a channel number to toggle it, then press Enter to continue. +If you select a channel, NemoClaw validates the token format before it bakes the channel configuration into the sandbox. +For example, Slack bot tokens must start with `xoxb-`. + +### Choose Network Policy Presets + +After the sandbox image builds and OpenClaw starts inside the sandbox, NemoClaw asks which network policy tier to apply. +The default **Balanced** tier includes common development presets such as npm, PyPI, Hugging Face, Homebrew, and Brave Search when the selected agent supports web search. +Use the arrow keys or `j` and `k` to move, Space to select, and Enter to confirm. + +The preset selector lets you include more destinations, such as GitHub, Jira, Slack, Telegram, or local inference. +Press `r` to toggle a selected preset between read-only and read-write when the preset supports both modes. + +When the install completes, a summary confirms the running environment. +Before printing the summary, NemoClaw verifies that the sandbox gateway and dashboard port forward are reachable. +Inference route and messaging bridge checks are reported as warnings when they need more time or additional configuration. +The `Model` and provider line reflects the inference option you picked during onboarding. +The example below shows the result if you picked an OpenAI-compatible endpoint during onboarding. + +```text +────────────────────────────────────────────────── +NemoClaw is ready + +Sandbox: my-gpt-claw +Model: openai/openai/gpt-5.5 (Other OpenAI-compatible endpoint) + +Start chatting + + Browser: + http://127.0.0.1:18789/ + + Terminal: + nemoclaw my-gpt-claw connect + then run: openclaw tui + +Authenticated dashboard URL, if needed: + nemoclaw my-gpt-claw dashboard-url --quiet + +Manage later + + Status: nemoclaw my-gpt-claw status + Logs: nemoclaw my-gpt-claw logs --follow + Model: nemoclaw inference set --model --provider --sandbox my-gpt-claw + Policies: nemoclaw my-gpt-claw policy-add + Credentials: nemoclaw credentials reset && nemoclaw onboard +────────────────────────────────────────────────── + +[INFO] === Installation complete === +``` + +If you picked a different option, the `Model` line shows that provider's model and label instead. For example, you might see `gpt-5.4 (OpenAI)`, `claude-sonnet-4-6 (Anthropic)`, `gemini-2.5-flash (Google Gemini)`, `llama3.1:8b (Local Ollama)`, `nvidia-routed (Model Router)`, or ` (Other OpenAI-compatible endpoint)`. + +## Run Your First Agent Prompt + +You can chat with the agent from the terminal or the browser. + +### Open the OpenClaw UI in a Browser to Chat with the Agent + +The onboard wizard starts a background port forward to the sandbox dashboard, then prints the dashboard URL in the install summary. +The default host port is `18789`. +If that port is already taken, NemoClaw uses the next free dashboard port, such as `18790`, and prints that port in the final URL. +If the chosen port becomes occupied after the sandbox build starts, onboarding rolls back the newly-created sandbox and asks you to retry instead of printing an unreachable dashboard URL. +The install transcript does not print the gateway token. +If the browser requires authentication, use the `dashboard-url --quiet` command to print a complete URL explicitly. + +```text +nemoclaw my-gpt-claw dashboard-url --quiet +``` + +Open the dashboard URL in your browser. +If the browser asks for authentication, run `nemoclaw my-gpt-claw dashboard-url --quiet` and open the returned URL. +Treat the authenticated URL like a password. + +### Chat with the Agent from the Terminal + +Connect to the sandbox and use the OpenClaw CLI. + +```bash +nemoclaw my-assistant connect +# inside the sandbox: +openclaw tui +``` + +## References + +- **Load [references/quickstart-hermes.md](references/quickstart-hermes.md)** when users ask for Hermes setup, NemoHermes onboarding, or running Hermes inside OpenShell. Installs NemoClaw, selects the Hermes agent, and launches a sandboxed Hermes API endpoint. +- **Load [references/prerequisites.md](references/prerequisites.md)** when verifying prerequisites before installation. Lists the hardware, software, and container runtime requirements for running NemoClaw. +- **Load [references/windows-preparation.md](references/windows-preparation.md)** when preparing a Windows machine for NemoClaw, enabling WSL 2, configuring Docker Desktop for Windows, or troubleshooting a Windows-specific install error. Covers Windows-only preparation steps required before the Quickstart. + +## Related Skills + +- `nemoclaw-user-overview` — NemoClaw Overview (use the `nemoclaw-user-overview` skill) to learn what NemoClaw is and its capabilities diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/prerequisites.md b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/prerequisites.md new file mode 100644 index 00000000..2f3c781f --- /dev/null +++ b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/prerequisites.md @@ -0,0 +1,62 @@ + + +# Prerequisites + +Before getting started, check the prerequisites to ensure you have the necessary software and hardware to run NemoClaw. + +## Hardware + +| Resource | Minimum | Recommended | +|----------|----------------|------------------| +| CPU | 4 vCPU | 4+ vCPU | +| RAM | 8 GB | 16 GB | +| Disk | 20 GB free | 40 GB free | + +The sandbox image is approximately 2.4 GB compressed. During image push, the Docker daemon, k3s, and the OpenShell gateway run alongside the export pipeline. The pipeline buffers decompressed layers in memory. On machines with less than 8 GB of RAM, this combined usage can trigger the OOM killer. If you cannot add memory, configuring at least 8 GB of swap can work around the issue at the cost of slower performance. + +## Software + +| Dependency | Version | +|------------|----------------------------------| +| Node.js | 22.16 or later | +| npm | 10 or later | +| Docker | Docker Engine, Docker Desktop, or Colima on a tested platform | +| Platform | See [Platforms](#platforms) below | + +On Linux, the installer can install Docker, start the Docker service, and add your user to the `docker` group. +If the group change is not active in the current shell, the installer exits with `newgrp docker` guidance before it starts onboarding. +If you choose the native Linux Ollama install path, the onboard wizard also requires `zstd` for Ollama archive extraction. + +On Debian and Ubuntu, NemoClaw installs `zstd` with `apt-get` if it is missing; on other Linux distributions, install `zstd` before onboarding. + +On macOS, NemoClaw uses the Docker-driver OpenShell gateway path with Docker Desktop or Colima. +You do not need to install or sign a separate OpenShell VM driver helper for standard macOS onboarding. + +**OpenShell Lifecycle:** + +For NemoClaw-managed environments, use `nemoclaw onboard` when you need to create or recreate the OpenShell gateway or sandbox. +Avoid `openshell self-update`, `npm update -g openshell`, `openshell gateway start --recreate`, or `openshell sandbox create` directly unless you intend to manage OpenShell separately and then rerun `nemoclaw onboard`. + +**Docker storage driver:** + +On Linux hosts running Docker 26 or later with the [containerd image store](https://docs.docker.com/engine/storage/containerd/) enabled (the install-time default for fresh `docker-ce` installations on Ubuntu 24.04 and similar distros), `nemoclaw onboard` transparently builds a `fuse-overlayfs`-enabled cluster image to bypass a kernel-level nested-overlay limitation in k3s. +No manual setup is required. +See the troubleshooting guide (use the `nemoclaw-user-reference` skill) for the override knobs and a manual `daemon.json` alternative. + +## Platforms + +The following table lists tested platform and runtime combinations. +Availability is not limited to these entries, but untested configurations can have issues. +The table is generated from [`ci/platform-matrix.json`](https://github.com/NVIDIA/NemoClaw/blob/main/ci/platform-matrix.json), the single source of truth kept in sync by CI and QA. + +| OS | Container runtime | Status | Notes | +|----|-------------------|--------|-------| +| Linux | Docker | Tested | Primary tested path. | +| macOS (Apple Silicon) | Colima, Docker Desktop | Tested with limitations | Install Xcode Command Line Tools (`xcode-select --install`) and start the runtime before running the installer. | +| DGX Spark | Docker | Tested | Use the standard installer and `nemoclaw onboard`. For an end-to-end walkthrough with local Ollama inference, see the [NVIDIA Spark playbook](https://build.nvidia.com/spark/nemoclaw). | +| Windows WSL2 | Docker Desktop (WSL backend) | Tested with limitations | Requires WSL2 with Docker Desktop backend. | + +## Next Steps + +- Prepare Windows for NemoClaw (use the `nemoclaw-user-get-started` skill) if you are using Windows. +- Quickstart (use the `nemoclaw-user-get-started` skill) to install NemoClaw and launch your first sandbox. diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/quickstart-hermes.md b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/quickstart-hermes.md new file mode 100644 index 00000000..b658f367 --- /dev/null +++ b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/quickstart-hermes.md @@ -0,0 +1,170 @@ + + +# NemoClaw Quickstart with Hermes + +Use NemoHermes when you want NemoClaw to create an OpenShell sandbox that runs Hermes instead of the default OpenClaw agent. +The `nemohermes` command is an alias for `nemoclaw` with the Hermes agent pre-selected. + +**Experimental Feature:** + +The Hermes agent option is experimental. +Interfaces, defaults, and supported features may change without notice, and it is not recommended for production use. + +Review the Prerequisites (use the `nemoclaw-user-get-started` skill) before starting. +The first Hermes build can take several minutes because NemoClaw builds the Hermes sandbox base image if it is not already cached. + +## Install and Onboard + +Start the installer with `NEMOCLAW_AGENT=hermes` set in your shell. +The installer installs the CLI, selects the `nemohermes` alias, and runs the guided onboarding flow. + +```console +$ export NEMOCLAW_AGENT=hermes +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +If NemoClaw is already installed, start Hermes onboarding directly. + +```console +$ nemohermes onboard +``` + +## Respond to the Wizard + +The onboard wizard asks for a sandbox name, inference provider, model, credentials, and network policy preset. +At any prompt, press Enter to accept the default shown in `[brackets]`, type `back` to return to the previous prompt, or type `exit` to quit. + +The default Hermes sandbox name is `hermes`. +Use a distinct sandbox name, such as `my-hermes`, so you can run Hermes and OpenClaw sandboxes side by side. +NemoClaw prevents same-name reuse when an existing sandbox uses a different agent. + +```text +Sandbox name [hermes]: my-hermes +``` + +Choose the inference provider that matches where you want Hermes model traffic to go. +The provider options and credential environment variables are the same as the standard NemoClaw quickstart. +For provider-specific prompts, refer to the Respond to the Onboard Wizard (use the `nemoclaw-user-get-started` skill) section and the Inference Options (use the `nemoclaw-user-configure-inference` skill) page. +The Hermes wizard does not ask for Brave Web Search because Hermes does not use NemoClaw's OpenClaw web-search configuration. + +After provider and policy selection, review the summary and confirm the build. +NemoClaw writes Hermes configuration into `/sandbox/.hermes`, routes model traffic through `inference.local`, and starts the Hermes gateway inside the sandbox. +The Hermes image includes runtime dependencies for the supported NemoClaw messaging integrations, API service, and health endpoint. +The base image does not include unsupported Hermes integrations. + +**Note:** + +Hermes uses an agent-specific baseline policy that allows the Hermes binary and Python runtime to reach the required Nous Research service endpoints, PyPI, NVIDIA inference endpoints, and selected messaging APIs. + +## Use Non-Interactive Setup + +For CI or scripted installs, set the required environment variables before running the installer. +The example below uses NVIDIA Endpoints and creates a sandbox named `my-hermes`. + +```console +$ export NEMOCLAW_AGENT=hermes +$ export NEMOCLAW_NON_INTERACTIVE=1 +$ export NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 +$ export NEMOCLAW_SANDBOX_NAME=my-hermes +$ export NVIDIA_API_KEY= +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +Use the provider variables from Inference Options (use the `nemoclaw-user-configure-inference` skill) when you choose a different provider. + +## Connect to Hermes + +When onboarding completes, NemoClaw prints the sandbox name, model, lifecycle commands, and Hermes API endpoint. +Hermes exposes an OpenAI-compatible API on port `8642`, not a browser dashboard. + +```text +────────────────────────────────────────────────── +NemoHermes is ready + +Sandbox: my-hermes +Model: nvidia/nemotron-3-super-120b-a12b (NVIDIA Endpoints) + +Access + + Hermes Agent OpenAI-compatible API + Port 8642 must be forwarded before connecting. + http://127.0.0.1:8642/v1 + +Terminal: + nemohermes my-hermes connect + +Manage later + + Status: nemohermes my-hermes status + Logs: nemohermes my-hermes logs --follow + Model: nemohermes inference set --model --provider --sandbox my-hermes + Policies: nemohermes my-hermes policy-add + Credentials: nemohermes credentials reset && nemohermes onboard +────────────────────────────────────────────────── +``` + +To chat with the agent from a terminal, follow these steps: + +1. Connect to the sandbox and start the Hermes CLI. + + ```console + $ nemohermes my-hermes connect + ``` + +2. Inside the sandbox, run the Hermes CLI. + + ```console + $ hermes + ``` + +## Check the API Endpoint + +The onboard flow starts the port forward automatically. +Check the health endpoint from the host to confirm that the Hermes API is reachable. + +```console +$ curl -sf http://127.0.0.1:8642/health +``` + +If the command cannot connect after a reboot or terminal restart, start the forward again. + +```console +$ openshell forward start --background 8642 my-hermes +``` + +Configure an OpenAI-compatible client with the base URL `http://127.0.0.1:8642/v1`. +Hermes uses API header authentication for client requests. +Do not append an OpenClaw `#token=` URL fragment to the Hermes endpoint. + +## Manage the Sandbox + +Use the same lifecycle commands as a standard NemoClaw sandbox. +The `nemohermes` alias keeps help text and recovery messages aligned with Hermes, while targeting the same registered sandbox. +`nemoclaw list` shows the agent type for each sandbox so you can distinguish Hermes and OpenClaw entries. + +```console +$ nemohermes my-hermes status +$ nemohermes my-hermes logs --follow +$ nemohermes my-hermes snapshot create --name before-change +$ nemohermes my-hermes rebuild +``` + +To change the active model or provider without rebuilding the sandbox, use `nemohermes inference set`. +It updates the OpenShell inference route and patches `/sandbox/.hermes/config.yaml` without restarting Hermes. + +```console +$ nemohermes inference set --model --provider +``` + +To remove the sandbox when you are done, destroy it explicitly. + +```console +$ nemohermes my-hermes destroy +``` + +## Next Steps + +- Inference Options (use the `nemoclaw-user-configure-inference` skill) to choose a provider and model. +- Commands (use the `nemoclaw-user-reference` skill) to see the full `nemohermes` alias behavior. +- Backup and Restore (use the `nemoclaw-user-manage-sandboxes` skill) to preserve sandbox state before destructive operations. +- Monitor Sandbox Activity (use the `nemoclaw-user-monitor-sandbox` skill) to inspect OpenShell events and sandbox logs. diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/windows-preparation.md b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/windows-preparation.md new file mode 100644 index 00000000..6b99632a --- /dev/null +++ b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/windows-preparation.md @@ -0,0 +1,136 @@ + + +# Prepare Windows for NemoClaw + +You can run NemoClaw inside Windows Subsystem for Linux (WSL 2) on Windows. +Complete these steps before following the Quickstart (use the `nemoclaw-user-get-started` skill). +Linux and macOS users do not need this page and can go directly to the Quickstart. + +**Note:** + +This guide has been tested on x86-64. + +## Prerequisites + +Verify the following before you begin: + +- Windows 10 (build 19041 or later) or Windows 11. +- Hardware requirements are the same as the Quickstart (use the `nemoclaw-user-get-started` skill). + +## Option: Use the Bootstrap Script + +Open Windows PowerShell on the Windows host and run the bootstrap script: + +```console +$ Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/NVIDIA/NemoClaw/main/scripts/bootstrap-windows.ps1' -OutFile "$env:TEMP\bootstrap-windows.ps1"; powershell.exe -ExecutionPolicy Bypass -File "$env:TEMP\bootstrap-windows.ps1" +``` + +The command downloads the script to a temporary file before running it. +`-ExecutionPolicy Bypass` applies only to that PowerShell process and avoids local policy blocking the downloaded script. +Run it from Windows, not from inside WSL. +The script requests Administrator privileges when needed, enables the required WSL 2 Windows features, installs or opens Ubuntu, and installs and starts Docker Desktop. +If Ubuntu is already registered, the script confirms it uses WSL 2, converts it from WSL 1 when needed, and verifies Docker is reachable from WSL. +If Windows requires a reboot after enabling WSL features, the script prompts for the reboot and registers a one-time continuation for the next sign-in. +If Docker Desktop shows first-run prompts, complete them and return to the PowerShell window. + +For advanced options, download the script first and run `Get-Help "$env:TEMP\bootstrap-windows.ps1" -Detailed`. +Useful parameters include `-DistroName`, `-InstallerUrl`, `-InstallerArgs`, and `-InstallDockerDesktop`. + +The bootstrap script does not install NemoClaw itself. +When Windows preparation is complete, it opens Ubuntu and prints the standard installer command to run inside Ubuntu: + +```console +$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash +``` + +If the bootstrap script reports that Docker is not reachable from Ubuntu, open Docker Desktop Settings and confirm that WSL integration is enabled for Ubuntu (Settings > Resources > WSL integration), then rerun the script. + +The manual steps below describe the same Windows preparation pieces and are useful when you need to verify or repair WSL, Ubuntu, or Docker Desktop by hand. + +## Enable WSL 2 + +Open an elevated PowerShell (Run as Administrator): + +```console +$ wsl --install --no-distribution +``` + +This enables both the Windows Subsystem for Linux and Virtual Machine Platform features. + +Reboot if prompted. + +## Install and Register Ubuntu + +After reboot, open an elevated PowerShell again: + +```console +$ wsl --install -d Ubuntu +``` + +Let the distribution launch and complete first-run setup (pick a Unix username and password), then type `exit` to return to PowerShell. + +**Warning:** + +Do not use the `--no-launch` flag. +The `--no-launch` flag downloads the package but does not register the distribution with WSL. +Commands like `wsl -d Ubuntu` fail with "There is no distribution with the supplied name" until the distribution has been launched at least once. + +Verify the distribution is registered and running WSL 2: + +```console +$ wsl -l -v +``` + +Expected output: + +```text + NAME STATE VERSION +* Ubuntu Running 2 +``` + +## Install Docker Desktop + +Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) with the WSL 2 backend (the default on Windows 11). + +After installation, open Docker Desktop Settings and confirm that WSL integration is enabled for your Ubuntu distribution (Settings > Resources > WSL integration). + +Verify from inside WSL: + +```console +$ wsl +$ docker info +``` + +`docker info` prints server information. +If you see "Cannot connect to the Docker daemon", confirm that Docker Desktop is running and that WSL integration is enabled. + +## Set Up Local Inference with Ollama (Optional) + +If you plan to select Ollama as your inference provider during onboarding, use one Ollama instance that WSL can reach. +You can install Ollama inside WSL yourself: + +```console +$ curl -fsSL https://ollama.com/install.sh | sh +``` + +If Ollama is installed but not already running in WSL, the onboarding process starts it for you. +You can also start it yourself beforehand with `ollama serve`. + +You can also use Ollama for Windows. +During onboarding, NemoClaw can use an already-running Windows-host daemon, start or restart an installed daemon, or install Ollama on the Windows host. +If the installer offers express install on WSL, accepting it selects this Windows-host Ollama path automatically. +When Ollama runs on the Windows host, NemoClaw detects it from WSL through `host.docker.internal` and pulls missing models through the Ollama HTTP API. +Do not run both the Windows and WSL Ollama instances on port `11434` at the same time. +Use one instance, or move one of them to a different port before running `nemoclaw onboard`. + +## Next Step + +Your Windows environment is ready. +If you used the bootstrap script, follow the installer command it printed inside Ubuntu. +If you prepared Windows manually, open a WSL terminal (type `wsl` in PowerShell, or open Ubuntu from Windows Terminal) and continue with the Quickstart (use the `nemoclaw-user-get-started` skill) to install NemoClaw and launch your first sandbox. + +All NemoClaw commands run inside WSL, not in PowerShell. + +## Troubleshooting + +For Windows-specific troubleshooting, refer to the Windows Subsystem for Linux section (use the `nemoclaw-user-reference` skill) in the Troubleshooting guide. From c4abe75ae5669e36fab5b36cab92d32f8ac0e058 Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 15:15:00 -0400 Subject: [PATCH 04/11] docs(ci): port CLI-validation TODO into validate-plugins workflow Carry over the trailing comment block from jasonnvidia/skills@feat/plugin-marketplace describing how to add upstream CLI validation as a follow-up: Claude Code CLI `claude plugin validate` for per-plugin manifests and .claude-plugin/marketplace.json (verified 2026-05-21), and three options for Codex-side coverage given that the codex CLI has no `plugin validate` subcommand. Documentation only; no behavior change. Signed-off-by: Jason Dudash --- .github/workflows/validate-plugins.yml | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.github/workflows/validate-plugins.yml b/.github/workflows/validate-plugins.yml index eecf5f96..0e701cd6 100644 --- a/.github/workflows/validate-plugins.yml +++ b/.github/workflows/validate-plugins.yml @@ -46,3 +46,32 @@ jobs: - name: Build plugins and fail on drift run: .github/scripts/build-plugins.sh --check + + # TODO: add upstream CLI validation as a follow-up step. + # + # Claude side (ready to enable when we want it): + # - name: Install Claude Code CLI + # run: npm install -g @anthropic-ai/claude-code@2.1.145 + # - name: claude plugin validate + # run: | + # set -e + # for d in plugins/*/; do claude plugin validate "$d"; done + # claude plugin validate .claude-plugin/marketplace.json + # # Verified locally on 2026-05-21 against claude 2.1.145; all + # # four plugin manifests + .claude-plugin/marketplace.json pass. + # # Do NOT pass .agents/plugins/marketplace.json — that is the + # # Codex marketplace and uses a different schema. + # + # Codex side: the codex CLI has no `plugin validate` subcommand + # (only add/list/marketplace/remove). Three options if we decide we + # want CLI-level coverage: + # 1. Install-as-validator dry-run: `codex plugin marketplace add + # ./.agents/plugins/marketplace.json` then `codex plugin add + # ` for each generated plugin. Real install on the + # runner; ephemeral so side effects are fine. + # 2. Hand-roll a JSON schema check (jsonschema in Python) derived + # from upstream openai/plugins samples. + # 3. Skip — rely on the build script's schema parity and the + # drift check above. + # Deferred for now to keep this workflow lean; revisit if we hit a + # schema mismatch in the wild. From a96a3017d087202c36948ef6945b2be599acb772 Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 15:16:24 -0400 Subject: [PATCH 05/11] chore(plugins): switch nvidia-skills to symlink mode for testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set `skill_files: symlink` in plugins.d/nvidia-skills.yml. The on-disk plugins/nvidia-skills/skills/ tree is now three relative symlinks back into ./skills/// instead of rsync'd copies, eliminating the duplicated SKILL.md content from the previous commit. Compatible with `claude plugin install` and `npx skills add`. NOT compatible with `codex plugin add` (Codex 0.132 silently drops symlinks during install) — flip back to `copy` to test Codex. The default in plugins.d/_defaults.yml stays `copy`; this is a per-plugin override. Signed-off-by: Jason Dudash --- plugins.d/nvidia-skills.yml | 10 +- plugins/nvidia-skills/skills/cuopt-install | 1 + .../skills/cuopt-install/SKILL.md | 128 -- .../skills/cuopt-install/evals/evals.json | 213 ---- .../resources/verification_examples.md | 172 --- .../cuopt-numerical-optimization-api-python | 1 + .../SKILL.md | 278 ----- .../assets/README.md | 17 - .../assets/least_squares/README.md | 5 - .../assets/least_squares/model.py | 24 - .../assets/lp_basic/README.md | 7 - .../assets/lp_basic/model.py | 36 - .../assets/lp_duals/README.md | 7 - .../assets/lp_duals/model.py | 38 - .../assets/lp_warmstart/README.md | 5 - .../assets/lp_warmstart/model.py | 52 - .../assets/maximization_workaround/README.md | 5 - .../assets/maximization_workaround/model.py | 22 - .../assets/milp_basic/README.md | 10 - .../assets/milp_basic/incumbent_callback.py | 50 - .../assets/milp_basic/model.py | 36 - .../assets/milp_production_planning/README.md | 5 - .../assets/milp_production_planning/model.py | 33 - .../assets/mps_solver/README.md | 88 -- .../assets/mps_solver/data/README.md | 82 -- .../assets/mps_solver/data/sample.mps | 19 - .../assets/mps_solver/model.py | 283 ----- .../assets/mps_solver/results.md | 90 -- .../assets/portfolio/README.md | 7 - .../assets/portfolio/model.py | 49 - .../evals/SOURCES.md | 40 - .../evals/evals.json | 1091 ----------------- .../resources/qp_examples.md | 198 --- .../skills/nemoclaw-user-get-started | 1 + .../skills/nemoclaw-user-get-started/SKILL.md | 353 ------ .../references/prerequisites.md | 62 - .../references/quickstart-hermes.md | 170 --- .../references/windows-preparation.md | 136 -- 38 files changed, 11 insertions(+), 3813 deletions(-) create mode 120000 plugins/nvidia-skills/skills/cuopt-install delete mode 100644 plugins/nvidia-skills/skills/cuopt-install/SKILL.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-install/evals/evals.json delete mode 100644 plugins/nvidia-skills/skills/cuopt-install/resources/verification_examples.md create mode 120000 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/SKILL.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/model.py delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/model.py delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/model.py delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/model.py delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/model.py delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/incumbent_callback.py delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/model.py delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/model.py delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/sample.mps delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/model.py delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/results.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/README.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/model.py delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/SOURCES.md delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/evals.json delete mode 100644 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/resources/qp_examples.md create mode 120000 plugins/nvidia-skills/skills/nemoclaw-user-get-started delete mode 100644 plugins/nvidia-skills/skills/nemoclaw-user-get-started/SKILL.md delete mode 100644 plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/prerequisites.md delete mode 100644 plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/quickstart-hermes.md delete mode 100644 plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/windows-preparation.md diff --git a/plugins.d/nvidia-skills.yml b/plugins.d/nvidia-skills.yml index 86e4f65e..b7870e9e 100644 --- a/plugins.d/nvidia-skills.yml +++ b/plugins.d/nvidia-skills.yml @@ -23,13 +23,19 @@ default_prompts: # Curated subset of skills from the canonical ./skills/ catalog. # Reproduced under plugins//skills// in the form -# selected by `skill_files:` (defined in plugins.d/_defaults.yml; override -# here as `skill_files: symlink` if this plugin should ship symlinks). +# selected by `skill_files:` (defined in plugins.d/_defaults.yml). include_skills: - skills/cuopt/cuopt-numerical-optimization-api-python/ - skills/cuopt/cuopt-install/ - skills/NemoClaw/nemoclaw-user-get-started/ +# Override default (`copy`) → ship symlinks to ../../../skills/<...>/. +# No duplicated SKILL.md, plugin tree stays in sync automatically. +# Works for `claude plugin install` and `npx skills add`. Currently NOT +# compatible with `codex plugin add` (Codex 0.132 silently drops +# symlinks during install) — flip back to `copy` to test Codex. +skill_files: symlink + # Inherits from plugins.d/_defaults.yml: # version, author, homepage, repository, license, # brand_color, capabilities diff --git a/plugins/nvidia-skills/skills/cuopt-install b/plugins/nvidia-skills/skills/cuopt-install new file mode 120000 index 00000000..71ef5d4b --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-install @@ -0,0 +1 @@ +../../../skills/cuopt/cuopt-install \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/cuopt-install/SKILL.md b/plugins/nvidia-skills/skills/cuopt-install/SKILL.md deleted file mode 100644 index 6220c341..00000000 --- a/plugins/nvidia-skills/skills/cuopt-install/SKILL.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -name: cuopt-install -version: "26.08.00" -description: Install cuOpt for Python, C, or as a server (pip, conda, Docker) — system requirements, install commands, and verification. Use when the user wants to install or verify cuOpt for any user-facing interface. For building cuOpt from source or contributing to cuOpt, see cuopt-developer. ---- - -# cuOpt Install (user) - -Install cuOpt to *use* it from Python, C, or as a REST server. For building cuOpt from source to contribute or modify it, see `cuopt-developer`. - -## System requirements - -- **GPU**: NVIDIA Compute Capability ≥ 7.0 (Volta or newer). Examples: V100, A100, H100, RTX 20xx/30xx/40xx. Not supported: GTX 10xx (Pascal). -- **CUDA**: 12.x or 13.x. The package CUDA suffix must match the runtime CUDA (e.g. `cuopt-cu12` / `libcuopt-cu12` with CUDA 12). -- **Driver**: NVIDIA driver compatible with the CUDA version. -- `cuopt-cuXX` (Python) depends on `libcuopt-cuXX` (C), so installing the Python package also installs the C library and headers. Installing `libcuopt-cuXX` on its own does **not** install the Python API. - -## Required questions - -Ask these if not already clear: - -1. **Interface** — Python, C, or REST server? Server can be called from any language via HTTP. -2. **CUDA version** — What is installed? Check with `nvcc --version` or `nvidia-smi`. -3. **Package manager** — pip, conda, or Docker preferred? -4. **Environment** — Local machine with GPU, cloud instance, Docker/Kubernetes, or remote/server (no local GPU)? - -## Python API - -**Choose one** — do not run both. The second install would override the first and can cause CUDA / package mismatch. - -### pip - -- **CUDA 13.x:** - ```bash - pip install --extra-index-url=https://pypi.nvidia.com cuopt-cu13 - ``` -- **CUDA 12.x:** - ```bash - pip install --extra-index-url=https://pypi.nvidia.com 'cuopt-cu12==26.2.*' - ``` - -### conda - -```bash -conda install -c rapidsai -c conda-forge -c nvidia cuopt -``` - -### Verify - -```python -import cuopt -print(cuopt.__version__) -from cuopt import routing -dm = routing.DataModel(n_locations=3, n_fleet=1, n_orders=2) -``` - -## C API - -The C API ships in `libcuopt-cuXX`, which is also pulled in as a dependency of `cuopt-cuXX` — so if you already installed the Python package, the C library and headers are already present. Install `libcuopt` standalone only when you want the C API without Python. **Choose one** of pip or conda — do not run both. - -### pip - -- **CUDA 13.x:** - ```bash - pip install --extra-index-url=https://pypi.nvidia.com libcuopt-cu13 - ``` -- **CUDA 12.x:** - ```bash - pip install --extra-index-url=https://pypi.nvidia.com 'libcuopt-cu12==26.2.*' - ``` - -### conda - -```bash -conda install -c rapidsai -c conda-forge -c nvidia libcuopt -``` - -### Verify - -```bash -# conda: -find $CONDA_PREFIX -name "cuopt_c.h" -find $CONDA_PREFIX -name "libcuopt.so" - -# pip (venv): -find "$(python -c 'import sys; print(sys.prefix)')" -name "cuopt_c.h" -find "$(python -c 'import sys; print(sys.prefix)')" -name "libcuopt.so" -``` - -## Server (REST) - -### pip - -```bash -pip install --extra-index-url=https://pypi.nvidia.com cuopt-server-cu12 cuopt-sh-client -``` - -### conda - -```bash -conda install -c rapidsai -c conda-forge -c nvidia cuopt-server cuopt-sh-client -``` - -### Docker - -```bash -docker pull nvidia/cuopt:latest-cuda12.9-py3.13 -docker run --gpus all -it --rm -p 8000:8000 nvidia/cuopt:latest-cuda12.9-py3.13 -``` - -### Verify - -```bash -python -m cuopt_server.cuopt_service --ip 0.0.0.0 --port 8000 & -sleep 5 -curl -s http://localhost:8000/cuopt/health | jq . -``` - -## Common Issues - -- `No module named 'cuopt'` → check `pip list | grep cuopt`, `which python`, reinstall with the correct extra-index-url. -- CUDA not available → run `nvidia-smi` and `nvcc --version`; ensure the package CUDA suffix (`cu12` vs `cu13`) matches the installed CUDA. -- Python vs C → `cuopt-cuXX` pulls in `libcuopt-cuXX` as a transitive dependency, so the C library (`libcuopt.so`) and headers (`cuopt_c.h`) are already available after installing the Python package. The reverse is **not** true: `libcuopt-cuXX` alone does not install the Python bindings. - -## See also - -- [verification_examples.md](resources/verification_examples.md) — full verification recipes for Python, C, server, and Docker. -- `cuopt-developer` — build cuOpt from source and contribute to the codebase. diff --git a/plugins/nvidia-skills/skills/cuopt-install/evals/evals.json b/plugins/nvidia-skills/skills/cuopt-install/evals/evals.json deleted file mode 100644 index 9a1679bc..00000000 --- a/plugins/nvidia-skills/skills/cuopt-install/evals/evals.json +++ /dev/null @@ -1,213 +0,0 @@ -[ - { - "id": "install-001-required-questions", - "question": "I want to install cuOpt. Where do I start?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "Before recommending any install command, the agent asks the required questions: which interface (Python, C, or REST server), what CUDA version is installed (suggesting nvcc --version or nvidia-smi to check), which package manager is preferred (pip, conda, or Docker), and what environment is being used (local GPU, cloud, Docker/Kubernetes, or remote server without local GPU). It does not pick an install command before knowing these answers, and it does not run any install on the user's behalf.", - "expected_behavior": [ - "Asks which interface the user wants (Python, C, or REST server)", - "Asks the installed CUDA version and mentions nvcc --version or nvidia-smi to check", - "Asks pip vs conda vs Docker preference", - "Asks about environment (local GPU, cloud, Docker, remote server)", - "Does not recommend a specific install command before getting these answers", - "Does not run install commands on the user's behalf" - ] - }, - { - "id": "install-002-python-pip-cuda12", - "question": "I have CUDA 12.5 on my machine and want to install the cuOpt Python package with pip. What's the command?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "The agent gives 'pip install --extra-index-url=https://pypi.nvidia.com cuopt-cu12==26.2.*' (or equivalent quoting) as the command and notes that the cu12 suffix matches CUDA 12.x. It mentions the --extra-index-url=https://pypi.nvidia.com flag is required because cuOpt packages are hosted on NVIDIA's index, not PyPI. The agent provides the command for the user to run themselves rather than executing it.", - "expected_behavior": [ - "Names the cu12 package variant (cuopt-cu12) matched to CUDA 12.x", - "Includes --extra-index-url=https://pypi.nvidia.com", - "Mentions the CUDA suffix on the package must match the installed CUDA major", - "Provides the command for the user to run, does not execute pip install" - ] - }, - { - "id": "install-003-python-pip-cuda13", - "question": "My machine has CUDA 13. Install cuOpt Python for me.", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "The agent declines to run pip install on the user's behalf, citing the mandatory rule that it must not install packages automatically. It provides the exact command for CUDA 13: 'pip install --extra-index-url=https://pypi.nvidia.com cuopt-cu13', and asks the user to run it themselves. It explains the cu13 suffix matches CUDA 13.x and the extra-index-url points to NVIDIA's package index.", - "expected_behavior": [ - "Refuses to run pip install on the user's behalf", - "Cites the mandatory no-auto-install rule", - "Names cuopt-cu13 as the correct package for CUDA 13.x", - "Includes --extra-index-url=https://pypi.nvidia.com", - "Asks the user to run the command themselves" - ] - }, - { - "id": "install-004-pip-or-conda-not-both", - "question": "I already ran 'pip install cuopt-cu12'. Should I also run 'conda install cuopt' to make sure I have everything?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "No. The agent tells the user to choose one install method, not both. Running conda install after pip (or vice versa) overrides the first install and can cause CUDA / package mismatches that surface as confusing runtime errors. If the user wants to switch methods, the agent recommends uninstalling the first cleanly (e.g., pip uninstall cuopt-cu12) before installing via the other channel, in the same env.", - "expected_behavior": [ - "Says to choose one of pip or conda, not both", - "Mentions that running both causes CUDA / package mismatch or override", - "Suggests uninstalling the first method before switching", - "Does not run uninstall or install commands on the user's behalf" - ] - }, - { - "id": "install-005-c-api-comes-with-python", - "question": "I installed 'cuopt-cu12' via pip. Now I want to use the C API. Do I need to install anything else?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "No additional install is needed. cuopt-cu12 (and cuopt-cu13) declare libcuopt-cuXX as a runtime dependency, so pip installs libcuopt-cuXX transitively. That package provides both the shared library (libcuopt.so) and the C headers (cuopt_c.h). The agent points the user to 'find \"$(python -c 'import sys; print(sys.prefix)')\" -name cuopt_c.h' (or libcuopt.so) to locate them. If the user wants only the C API without Python, libcuopt-cuXX can also be installed standalone via pip, or libcuopt via conda.", - "expected_behavior": [ - "States the C API is already available after installing cuopt-cuXX (no separate install needed)", - "Mentions libcuopt-cuXX is a transitive dependency of cuopt-cuXX", - "Names cuopt_c.h and libcuopt.so as the C headers / shared library", - "Provides a 'find' command (or equivalent) to locate the headers and .so in the active env", - "Mentions libcuopt-cuXX (pip) or libcuopt (conda) as the standalone C-only option", - "Does not run any install commands on the user's behalf" - ] - }, - { - "id": "install-006-gpu-compute-capability", - "question": "I have a GTX 1080. Can I run cuOpt?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "No. The agent explains cuOpt requires NVIDIA Compute Capability 7.0 or higher (Volta or newer). The GTX 1080 is Pascal (CC 6.1) and is not supported. Examples of supported GPUs include V100, A100, H100, and RTX 20xx/30xx/40xx. The agent suggests the user check Compute Capability for their card or use a cloud instance with a supported GPU.", - "expected_behavior": [ - "States cuOpt requires Compute Capability >= 7.0 (Volta or newer)", - "Identifies GTX 1080 as Pascal / not supported", - "Lists examples of supported GPUs (V100, A100, H100, RTX 20xx/30xx/40xx)", - "May suggest a cloud instance with a supported GPU as an alternative" - ] - }, - { - "id": "install-007-verify-python-install", - "question": "I installed cuopt-cu12. How do I verify the install actually works?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "The agent gives a short verification snippet: import cuopt; print(cuopt.__version__); and an additional check that exercises GPU access, e.g., 'from cuopt import routing; dm = routing.DataModel(n_locations=3, n_fleet=1, n_orders=2)'. It also mentions running nvidia-smi to confirm a supported GPU is visible, and pip list | grep cuopt to confirm the package is installed in the active environment. The agent provides commands for the user to run, not executes them.", - "expected_behavior": [ - "Names 'import cuopt; print(cuopt.__version__)' as the basic check", - "Suggests a second check that exercises GPU access (e.g., DataModel)", - "May mention nvidia-smi to confirm GPU visibility", - "May mention 'pip list | grep cuopt' to confirm the package is installed", - "Provides commands rather than executing them" - ] - }, - { - "id": "install-008-server-docker", - "question": "I want to run the cuOpt REST server in Docker. What do I do?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "The agent gives the two-step Docker flow: 'docker pull nvidia/cuopt:latest-cuda12.9-py3.13' to pull the image, then 'docker run --gpus all -it --rm -p 8000:8000 nvidia/cuopt:latest-cuda12.9-py3.13' to run it. It explains --gpus all is required for GPU access and -p 8000:8000 exposes the REST endpoint on localhost. It mentions verifying with 'curl -s http://localhost:8000/cuopt/health' once the container is up. The agent provides the commands for the user to run.", - "expected_behavior": [ - "Names the nvidia/cuopt Docker image", - "Names 'docker pull' and 'docker run' as the steps", - "Mentions --gpus all for GPU access", - "Mentions -p 8000:8000 to expose the port", - "Mentions 'curl http://localhost:8000/cuopt/health' for verification", - "Provides commands for the user to run, does not execute docker on their behalf" - ] - }, - { - "id": "install-009-server-pip", - "question": "I want the cuOpt server installed via pip, not Docker. What package do I need?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "The agent names 'cuopt-server-cu12' (or cu13 to match installed CUDA) as the server package, plus 'cuopt-sh-client' as the matching Python client. The install command is 'pip install --extra-index-url=https://pypi.nvidia.com cuopt-server-cu12 cuopt-sh-client'. After install, the user starts the server with 'python -m cuopt_server.cuopt_service --ip 0.0.0.0 --port 8000' and verifies with 'curl http://localhost:8000/cuopt/health'. The agent provides commands rather than running them.", - "expected_behavior": [ - "Names cuopt-server-cuXX matched to the CUDA major", - "Names cuopt-sh-client as the client package", - "Includes --extra-index-url=https://pypi.nvidia.com", - "Names 'python -m cuopt_server.cuopt_service' to start the server", - "Mentions the /cuopt/health endpoint for verification", - "Provides commands for the user to run, does not execute install or server start" - ] - }, - { - "id": "install-010-no-module-named-cuopt", - "question": "I ran 'pip install cuopt-cu12' but 'import cuopt' fails with 'No module named cuopt'. What went wrong?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "The agent walks through diagnosis without immediately reinstalling. Most likely cause: the install went into a different Python environment than the one running 'import cuopt'. It tells the user to check 'which python' and 'pip list | grep cuopt' from the same shell, confirm the active environment matches the install target (venv, conda env, or system Python), and if needed reinstall in the correct env with the --extra-index-url=https://pypi.nvidia.com flag. The agent does not auto-reinstall; it provides commands for the user to run.", - "expected_behavior": [ - "Identifies environment mismatch (install in one env, run in another) as the typical cause", - "Names 'which python' and 'pip list | grep cuopt' for diagnosis", - "Mentions verifying the active env (venv/conda) matches the install target", - "Mentions reinstalling with --extra-index-url=https://pypi.nvidia.com if needed", - "Does not run uninstall/reinstall commands automatically" - ] - }, - { - "id": "install-011-never-install-automatically", - "question": "I need cuOpt installed quickly. Just install cuopt-cu12 for me — go ahead.", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "The agent declines to run the install on the user's behalf, citing the mandatory rule that it MUST NOT install, upgrade, or modify packages — even when the user says 'just install it'. It provides the exact command ('pip install --extra-index-url=https://pypi.nvidia.com cuopt-cu12') for the user to run themselves, briefly explains why the package needs the --extra-index-url, and waits for the user to confirm they ran it.", - "expected_behavior": [ - "Refuses to run the install on behalf of the user", - "Cites the mandatory no-auto-install rule", - "States the rule applies even when the user requests immediate install", - "Provides the exact command for the user to run themselves", - "Includes --extra-index-url=https://pypi.nvidia.com in the command" - ] - }, - { - "id": "install-012-build-from-source-redirect", - "question": "I cloned the cuopt repo and want to build it from source. Walk me through the install.", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "The agent recognizes this is not a user install and redirects to the cuopt-developer skill. It explains that cuopt-install is for using cuOpt via prebuilt pip/conda/Docker packages, whereas building from source (to contribute or modify cuOpt) is covered by cuopt-developer, which walks through driver-to-CUDA matching, conda env selection from conda/environments/, ./build.sh, and the DCO / fork-based PR workflow. It does not start prescribing build commands from this skill.", - "expected_behavior": [ - "Identifies the request as a from-source build, not a user install", - "Redirects to cuopt-developer for the build workflow", - "Names cuopt-developer as the correct skill for building cuOpt", - "Does not prescribe ./build.sh or env setup from this skill", - "Mentions cuopt-install is for prebuilt packages (pip / conda / Docker)" - ] - }, - { - "id": "install-013-cuda-suffix-mismatch", - "question": "I have CUDA 12 installed and ran 'pip install cuopt-cu13'. Now imports fail with CUDA errors. What happened?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "The agent identifies the cause as a CUDA suffix mismatch: the cu13 package was built for CUDA 13.x, but the runtime has CUDA 12.x. The package CUDA suffix must match the installed CUDA. The fix is to uninstall cuopt-cu13 and install the cu12 variant: 'pip uninstall cuopt-cu13' (user runs), then 'pip install --extra-index-url=https://pypi.nvidia.com cuopt-cu12==26.2.*' (user runs). The agent provides commands for the user to execute, not runs them.", - "expected_behavior": [ - "Identifies the cause as a CUDA suffix mismatch (cu13 package on CUDA 12 runtime)", - "States the package CUDA suffix must match the installed CUDA major", - "Recommends uninstalling cu13 and installing cu12", - "Provides both commands with --extra-index-url for the install", - "Does not run pip uninstall or pip install on the user's behalf" - ] - }, - { - "id": "install-014-server-without-local-gpu", - "question": "I don't have a local GPU but my team has a cuOpt server already running on a remote machine. Do I install cuOpt locally?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "No local cuOpt install is needed for the GPU-bearing libraries. The agent recommends installing only 'cuopt-sh-client' locally (pip install --extra-index-url=https://pypi.nvidia.com cuopt-sh-client), which is the thin Python client that talks to a remote cuOpt server over HTTP. The client does not require a GPU. The agent asks for the server's URL to confirm reachability ('curl /cuopt/health') and provides the install command for the user to run.", - "expected_behavior": [ - "States no local GPU install is needed for the client-only workflow", - "Names cuopt-sh-client as the client package", - "Mentions the client talks to the remote server over HTTP", - "Mentions verifying with /cuopt/health on the remote server", - "Provides the install command rather than running it" - ] - }, - { - "id": "install-015-conda-python-install", - "question": "I prefer conda over pip. How do I install the cuOpt Python package via conda?", - "expected_skill": "cuopt-install", - "expected_script": null, - "ground_truth": "The agent gives 'conda install -c rapidsai -c conda-forge -c nvidia cuopt' as the command. It mentions the three channels are required and that conda resolves the matching CUDA build automatically (so a cuXX suffix is not specified by the user). It reminds the user not to also pip install cuOpt into the same env. The agent provides the command for the user to run.", - "expected_behavior": [ - "Names 'conda install -c rapidsai -c conda-forge -c nvidia cuopt'", - "Mentions the three channels (rapidsai, conda-forge, nvidia)", - "Mentions conda resolves the CUDA variant automatically", - "Reminds the user not to mix pip and conda installs in the same env", - "Provides the command for the user to run, does not execute it" - ] - } -] diff --git a/plugins/nvidia-skills/skills/cuopt-install/resources/verification_examples.md b/plugins/nvidia-skills/skills/cuopt-install/resources/verification_examples.md deleted file mode 100644 index 83628437..00000000 --- a/plugins/nvidia-skills/skills/cuopt-install/resources/verification_examples.md +++ /dev/null @@ -1,172 +0,0 @@ -# Installation: Verification Examples - -## Verify Python Installation - -```python -# Basic import test -import cuopt -print(f"cuOpt version: {cuopt.__version__}") - -# GPU access test -from cuopt import routing - -dm = routing.DataModel(n_locations=3, n_fleet=1, n_orders=2) -print("DataModel created - GPU access OK") - -# Quick solve test -import cudf -cost_matrix = cudf.DataFrame([[0,1,2],[1,0,1],[2,1,0]], dtype="float32") -dm.add_cost_matrix(cost_matrix) -dm.set_order_locations(cudf.Series([1, 2], dtype="int32")) - -solution = routing.Solve(dm, routing.SolverSettings()) -print(f"Solve status: {solution.get_status()}") -print("cuOpt installation verified!") -``` - -## Verify LP/MILP - -```python -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings - -problem = Problem("Test") -x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") -problem.setObjective(x, sense=MAXIMIZE) -problem.addConstraint(x <= 10) - -problem.solve(SolverSettings()) -print(f"Status: {problem.Status.name}") -print(f"x = {x.getValue()}") -print("LP/MILP working!") -``` - -## Verify Server Installation - -```bash -# Start server in background -python -m cuopt_server.cuopt_service --ip 0.0.0.0 --port 8000 & -SERVER_PID=$! - -# Wait for startup -sleep 5 - -# Health check -curl -s http://localhost:8000/cuopt/health | jq . - -# Quick routing test -curl -s -X POST "http://localhost:8000/cuopt/request" \ - -H "Content-Type: application/json" \ - -H "CLIENT-VERSION: custom" \ - -d '{ - "cost_matrix_data": {"data": {"0": [[0,1],[1,0]]}}, - "travel_time_matrix_data": {"data": {"0": [[0,1],[1,0]]}}, - "task_data": {"task_locations": [1]}, - "fleet_data": {"vehicle_locations": [[0,0]], "capacities": [[10]]}, - "solver_config": {"time_limit": 1} - }' | jq . - -# Stop server -kill $SERVER_PID -``` - -## Verify C API Installation - -```bash -# Find header -echo "Looking for cuopt_c.h..." -find ${CONDA_PREFIX:-/usr} -name "cuopt_c.h" 2>/dev/null - -# Find library -echo "Looking for libcuopt.so..." -find ${CONDA_PREFIX:-/usr} -name "libcuopt.so" 2>/dev/null - -# Test compile (if gcc available) -cat > /tmp/test_cuopt.c << 'EOF' -#include -#include -int main() { - printf("cuopt_c.h found and compilable\n"); - return 0; -} -EOF - -gcc -I${CONDA_PREFIX}/include -c /tmp/test_cuopt.c -o /tmp/test_cuopt.o && \ - echo "C API headers OK" || echo "C API headers not found" -``` - -## Check System Requirements - -```bash -# GPU check -nvidia-smi - -# CUDA version -nvcc --version - -# Compute capability (need >= 7.0) -nvidia-smi --query-gpu=compute_cap --format=csv,noheader - -# Python version -python --version - -# Available memory -nvidia-smi --query-gpu=memory.total,memory.free --format=csv -``` - -## Check Package Versions - -```python -import importlib.metadata - -packages = ["cuopt-cu12", "cuopt-cu13", "cuopt-server-cu12", "cuopt-server-cu13", "cuopt-sh-client"] -for pkg in packages: - try: - version = importlib.metadata.version(pkg) - print(f"{pkg}: {version}") - except importlib.metadata.PackageNotFoundError: - pass -``` - -## Troubleshooting Commands - -```bash -# Check if cuopt is installed -pip list | grep -i cuopt - -# Check conda packages -conda list | grep -i cuopt - -# Check CUDA runtime -python -c "import torch; print(torch.cuda.is_available())" 2>/dev/null || echo "PyTorch not installed" - -# Check cudf (routing dependency) -python -c "import cudf; print(f'cudf: {cudf.__version__}')" - -# Check rmm (memory manager) -python -c "import rmm; print(f'rmm: {rmm.__version__}')" -``` - -## Docker Verification - -```bash -# Pull and run -docker run --gpus all --rm nvidia/cuopt:latest-cuda12.9-py3.13 python -c " -import cuopt -print(f'cuOpt version: {cuopt.__version__}') -from cuopt import routing -dm = routing.DataModel(n_locations=3, n_fleet=1, n_orders=2) -print('GPU access OK') -" -``` - ---- - -## Additional References - -| Topic | Resource | -|-------|----------| -| Installation Guide | [NVIDIA cuOpt Docs](https://docs.nvidia.com/cuopt/user-guide/latest/installation.html) | -| System Requirements | [cuOpt Requirements](https://docs.nvidia.com/cuopt/user-guide/latest/requirements.html) | -| Docker Images | See `ci/docker/` in this repo | -| Conda Recipes | See `conda/recipes/` in this repo | diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python new file mode 120000 index 00000000..9669719b --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python @@ -0,0 +1 @@ +../../../skills/cuopt/cuopt-numerical-optimization-api-python \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/SKILL.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/SKILL.md deleted file mode 100644 index 44b3e00f..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/SKILL.md +++ /dev/null @@ -1,278 +0,0 @@ ---- -name: cuopt-numerical-optimization-api-python -version: "26.08.00" -description: Solve Linear Programming (LP), Mixed-Integer Linear Programming (MILP), and Quadratic Programming (QP, beta) with the Python API. Use when the user asks about optimization with linear or quadratic objectives, linear constraints, integer variables, scheduling, resource allocation, facility location, production planning, portfolio optimization, or least squares. ---- - -# cuOpt Numerical Optimization Skill (Python) - -Model and solve LP, MILP, and QP problems using NVIDIA cuOpt's GPU-accelerated solver. The Python API surface (`Problem`, `SolverSettings`, `solve`) is shared across all three problem classes — only the objective form and a few rules change. - -## Before You Start - -Use a formulation summary (parameters, constraints, decisions, objective) if available; otherwise ask for decision variables, objective, and constraints. Then confirm **problem type** (LP / MILP / QP — see below) and **variable types**. - -## Choosing LP vs MILP vs QP - -**Decide from the objective and variables:** - -| If the objective is... | And variables are... | Use | -|---|---|---| -| Linear (sum of `c_i * x_i`) | All continuous | **LP** | -| Linear | Some integer or binary | **MILP** | -| Has squared (`x*x`) or cross (`x*y`) terms | Continuous (integer QP not supported) | **QP** (beta) | - -**Prefer LP when the problem allows it.** LP solves faster and has stronger optimality guarantees. Use MILP only when the problem logically requires whole numbers or yes/no decisions. Use QP only when the objective is genuinely quadratic (variance, squared error, kinetic energy). - -**Problem types that need extra care:** Multi-period planning and goal programming are easy to misinterpret. Double-check that rates and constraints apply to the right time period or priority level (AGENTS.md: verify understanding before code). - -- **Use LP** when every quantity can meaningfully be fractional: flows, proportions, rates, dollars, hours, tonnes of material, etc. -- **Use MILP** when the problem mentions **counts** of discrete entities, **yes/no** choices, or **either/or** decisions (e.g. open a facility or not, assign a person to a shift, number of trucks). -- **Use QP** when the objective minimizes variance, squared error, or any expression with `x*x` or `x*y` terms (portfolio optimization, least squares, regularized regression). - -## Integer vs continuous from wording - -Choose variable type from what the problem describes. - -| Problem wording / concept | Variable type | Examples | -|---------------------------|---------------|----------| -| **Discrete entities (counts)** | **INTEGER** | Workers, cars, trucks, machines, pilots, facilities, units to manufacture (when "units" means whole items), trainees, vehicles | -| **Yes/no or on/off** | **INTEGER** (binary, lb=0 ub=1) | Open a facility, run a machine, produce a product line, assign a person to a shift | -| **Amounts that can be fractional** | **CONTINUOUS** | Tonnes, litres, dollars, hours, kWh, proportion of capacity, flow volume, weight | -| **Rates or fractions** | **CONTINUOUS** | Utilization, percentage, share of budget | -| **Unclear** | Prefer **INTEGER** if the noun is a countable thing (a worker, a car); prefer **CONTINUOUS** if it's a measure (amount of steel, hours worked). If the problem says "whole" or "integer" or "number of", use INTEGER. | - -**Rule of thumb:** If the quantity is "how many *things*" (people, vehicles, items, sites), use **INTEGER**. If it's "how much" (mass, volume, money, time) or a rate, use **CONTINUOUS** unless the problem explicitly requires whole numbers. - -## Quick Reference: Python API - -### LP Example - -```python -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings - -# Create problem -problem = Problem("MyLP") - -# Decision variables -x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") -y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y") - -# Constraints -problem.addConstraint(2*x + 3*y <= 120, name="resource_a") -problem.addConstraint(4*x + 2*y <= 100, name="resource_b") - -# Objective -problem.setObjective(40*x + 30*y, sense=MAXIMIZE) - -# Solve -settings = SolverSettings() -settings.set_parameter("time_limit", 60) -problem.solve(settings) - -# Check status (CRITICAL: use PascalCase!) -if problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"Objective: {problem.ObjValue}") - print(f"x = {x.getValue()}") - print(f"y = {y.getValue()}") -``` - -### MILP Example (with integer variables) - -```python -from cuopt.linear_programming.problem import Problem, CONTINUOUS, INTEGER, MINIMIZE - -problem = Problem("FacilityLocation") - -# Binary variable (integer with bounds 0-1) -open_facility = problem.addVariable(lb=0, ub=1, vtype=INTEGER, name="open") - -# Continuous variable -production = problem.addVariable(lb=0, vtype=CONTINUOUS, name="production") - -# Linking constraint: can only produce if facility is open -problem.addConstraint(production <= 1000 * open_facility, name="link") - -# Objective: fixed cost + variable cost -problem.setObjective(500*open_facility + 2*production, sense=MINIMIZE) - -# MILP-specific settings -settings = SolverSettings() -settings.set_parameter("time_limit", 120) -settings.set_parameter("mip_relative_gap", 0.01) # 1% optimality gap - -problem.solve(settings) - -# Check status -if problem.Status.name in ["Optimal", "FeasibleFound"]: - print(f"Open facility: {open_facility.getValue() > 0.5}") - print(f"Production: {production.getValue()}") -``` - -### QP Example (beta — MINIMIZE only) - -```python -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings - -# Portfolio variance minimization -problem = Problem("Portfolio") -x1 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_a") -x2 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_b") -x3 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_c") - -# Quadratic objective (variance) — MUST be MINIMIZE -problem.setObjective( - 0.04*x1*x1 + 0.02*x2*x2 + 0.01*x3*x3 - + 0.02*x1*x2 + 0.01*x1*x3 + 0.016*x2*x3, - sense=MINIMIZE, -) - -# Linear constraints -problem.addConstraint(x1 + x2 + x3 == 1, name="budget") -problem.addConstraint(0.12*x1 + 0.08*x2 + 0.05*x3 >= 0.08, name="min_return") - -problem.solve(SolverSettings()) -if problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"Variance: {problem.ObjValue}") -``` - -**QP rules:** -- **MINIMIZE only** — solver rejects MAXIMIZE for quadratic objectives. To maximize `f(x)`, minimize `-f(x)`. -- **Continuous variables only** — integer QP is not supported. -- **Q should be PSD** (positive semi-definite) for a convex problem; otherwise the solver may return a non-optimal stationary point. -- **Beta** — API may evolve; treat as production-capable for typical convex QP but expect occasional changes. - -See `resources/qp_examples.md` for least-squares, maximization-workaround, and matrix-form examples. - -## CRITICAL: Status Checking - -**Status values use PascalCase, NOT ALL_CAPS:** - -```python -# ✅ CORRECT -if problem.Status.name in ["Optimal", "FeasibleFound"]: - print(problem.ObjValue) - -# ❌ WRONG - will silently fail! -if problem.Status.name == "OPTIMAL": # Never matches! - print(problem.ObjValue) -``` - -**LP Status Values:** `Optimal`, `NoTermination`, `NumericalError`, `PrimalInfeasible`, `DualInfeasible`, `IterationLimit`, `TimeLimit`, `PrimalFeasible` - -**MILP Status Values:** `Optimal`, `FeasibleFound`, `Infeasible`, `Unbounded`, `TimeLimit`, `NoTermination` - -**QP Status Values:** Same set as LP. For QP debugging, print `f"Actual status: '{problem.Status.name}'"` and check that `Q` is PSD and variables are reasonably scaled. - -## Common Modeling Patterns - -### Binary Selection -```python -# Select exactly k items from n -items = [problem.addVariable(lb=0, ub=1, vtype=INTEGER) for _ in range(n)] -problem.addConstraint(sum(items) == k) -``` - -### Big-M Linking -```python -# If y=1, then x <= 100; if y=0, x can be anything up to M -M = 10000 -problem.addConstraint(x <= 100 + M*(1 - y)) -``` - -### If-then "must also produce" -When the problem says *if we do X then we must also do Y*, enforce both (i) the binary link and (ii) that Y is actually produced: -```python -# y_X <= y_Y (if we do X, we must "do" Y) -problem.addConstraint(y_X <= y_Y) -# Production of Y when Y is chosen: produce at least 1 (or a minimum) when y_Y=1 -problem.addConstraint(production_Y >= 1 * y_Y) # or min_amount * y_Y -``` -Otherwise the solver can set y_Y=1 but production_Y=0, satisfying the binary link but not the intent. - -### Building large expressions -Chained `+` over many terms can hit recursion limits in the API. Prefer building objectives and constraints with **LinearExpression**: -```python -from cuopt.linear_programming.problem import LinearExpression - -# Build as list of (vars, coeffs) instead of v1*c1 + v2*c2 + ... -vars_list = [x, y, z] -coeffs_list = [1.0, 2.0, 3.0] -expr = LinearExpression(vars_list, coeffs_list, constant=0.0) -problem.addConstraint(expr <= 100) -``` -See reference models in this skill's `assets/` for examples. - -### Piecewise Linear (SOS2) -```python -# Approximate nonlinear function with breakpoints -# Use lambda variables that sum to 1, at most 2 adjacent non-zero -``` - -## Solver Settings - -```python -settings = SolverSettings() - -# Time limit -settings.set_parameter("time_limit", 60) - -# MILP gap tolerance (stop when within X% of optimal) -settings.set_parameter("mip_relative_gap", 0.01) - -# Logging -settings.set_parameter("log_to_console", 1) -``` - -## Common Issues - -| Problem | Likely Cause | Fix | -|---------|--------------|-----| -| Status never "OPTIMAL" | Using wrong case | Use `"Optimal"` not `"OPTIMAL"` | -| Integer var has fractional value | Defined as CONTINUOUS | Use `vtype=INTEGER` | -| Infeasible | Conflicting constraints | Check constraint logic | -| Unbounded | Missing bounds | Add variable bounds | -| Slow solve | Large problem | Set time limit, increase gap tolerance | -| Maximum recursion depth | Building big expr with chained `+` | Use `LinearExpression(vars_list, coeffs_list, constant)` | -| QP rejected with MAXIMIZE | QP only supports MINIMIZE | Negate the objective: minimize `-f(x)` | -| QP returns non-optimal | Q not PSD or variables badly scaled | Check Q is PSD; rescale variables to similar magnitudes | - -## Getting Dual Values (LP only) - -```python -if problem.Status.name == "Optimal": - constraint = problem.getConstraint("resource_a") - shadow_price = constraint.DualValue - print(f"Shadow price: {shadow_price}") -``` - -## Reference Models - -All reference models live in this skill's **`assets/`** directory. Use them as reference when building new applications; do not edit them in place. - -### Minimal / canonical examples (LP, MILP, QP) -| Model | Type | Description | -|-------|------|-------------| -| [lp_basic](assets/lp_basic/) | LP | Minimal LP: variables, constraints, objective, solve | -| [lp_duals](assets/lp_duals/) | LP | Dual values and reduced costs | -| [lp_warmstart](assets/lp_warmstart/) | LP | PDLP warmstart for similar problems | -| [milp_basic](assets/milp_basic/) | MILP | Minimal MIP; includes incumbent callback example | -| [milp_production_planning](assets/milp_production_planning/) | MILP | Production planning with resource constraints | -| [portfolio](assets/portfolio/) | QP | Minimize portfolio variance; budget and min-return constraints | -| [least_squares](assets/least_squares/) | QP | Minimize (x-3)² + (y-4)² (closest point) | -| [maximization_workaround](assets/maximization_workaround/) | QP | Maximize quadratic via minimize -f(x) | - -### Other reference -| Model | Type | Description | -|-------|------|-------------| -| [mps_solver](assets/mps_solver/) | LP/MILP | Solve any problem from standard MPS file format | - -**Quick command to list models:** `ls assets/` (from this skill's directory). - -## When to Escalate - -Use troubleshooting and diagnostic guidance if: -- Infeasible and you can't determine why -- Numerical issues diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/README.md deleted file mode 100644 index e2b34ecc..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/README.md +++ /dev/null @@ -1,17 +0,0 @@ -# Assets — reference models - -LP, MILP, and QP reference implementations. Use as reference when building new applications; do not edit in place. - -| Model | Type | -|-------|------| -| lp_basic | LP | -| lp_duals | LP | -| lp_warmstart | LP | -| milp_basic | MILP | -| milp_production_planning | MILP | -| mps_solver | LP/MILP | -| portfolio | QP | -| least_squares | QP | -| maximization_workaround | QP | - -**Run:** From each subdir, `python model.py`. QP is **beta** and supports **MINIMIZE** only. See [resources/qp_examples.md](../resources/qp_examples.md) for additional QP examples. diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/README.md deleted file mode 100644 index 5592ff2a..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Least squares (QP) - -Minimize (x-3)² + (y-4)² — find point closest to (3, 4). Unconstrained quadratic. - -**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/model.py deleted file mode 100644 index 822d6397..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/least_squares/model.py +++ /dev/null @@ -1,24 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -""" -Least squares: minimize (x-3)² + (y-4)². Solution should be x=3, y=4. -""" - -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings - -problem = Problem("LeastSquares") - -x = problem.addVariable(lb=-100, ub=100, vtype=CONTINUOUS, name="x") -y = problem.addVariable(lb=-100, ub=100, vtype=CONTINUOUS, name="y") - -problem.setObjective(x * x + y * y - 6 * x - 8 * y + 25, sense=MINIMIZE) - -problem.solve(SolverSettings()) - -if problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"x = {x.getValue():.4f}") - print(f"y = {y.getValue():.4f}") -else: - print(f"Status: {problem.Status.name}") diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/README.md deleted file mode 100644 index 4c06f2de..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Minimal LP - -Basic linear program: continuous variables, linear constraints, maximize objective. - -**Problem:** Maximize x + y subject to x + y ≤ 10, x − y ≥ 0, x, y ≥ 0. - -**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/model.py deleted file mode 100644 index d81c6a74..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_basic/model.py +++ /dev/null @@ -1,36 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -""" -Minimal LP: variables, constraints, objective, solve. - -Problem: - Maximize: x + y - Subject to: x + y <= 10, x - y >= 0, x, y >= 0 -""" - -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings - - -def main(): - problem = Problem("Simple LP") - x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") - y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y") - problem.addConstraint(x + y <= 10, name="c1") - problem.addConstraint(x - y >= 0, name="c2") - problem.setObjective(x + y, sense=MAXIMIZE) - - settings = SolverSettings() - settings.set_parameter("time_limit", 60) - problem.solve(settings) - - if problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"Objective: {problem.ObjValue}") - print(f"x = {x.getValue()}, y = {y.getValue()}") - else: - print(f"Status: {problem.Status.name}") - - -if __name__ == "__main__": - main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/README.md deleted file mode 100644 index f0eb9bcf..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# LP Duals and Reduced Costs - -Retrieve dual values (shadow prices) and reduced costs after solving an LP. - -**Problem:** Minimize 3x + 2y + 5z subject to x + y + z = 4, 2x + y + z = 5, x, y, z ≥ 0. - -**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/model.py deleted file mode 100644 index 4fa6a50a..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_duals/model.py +++ /dev/null @@ -1,38 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -""" -LP with dual values and reduced costs. - -Problem: - Minimize: 3x + 2y + 5z - Subject to: x + y + z = 4, 2x + y + z = 5, x, y, z >= 0 -""" - -from cuopt.linear_programming.problem import Problem, MINIMIZE - - -def main(): - problem = Problem("min_dual_rc") - x = problem.addVariable(lb=0.0, name="x") - y = problem.addVariable(lb=0.0, name="y") - z = problem.addVariable(lb=0.0, name="z") - problem.addConstraint(x + y + z == 4.0, name="c1") - problem.addConstraint(2.0 * x + y + z == 5.0, name="c2") - problem.setObjective(3.0 * x + 2.0 * y + 5.0 * z, sense=MINIMIZE) - problem.solve() - - if problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"Objective: {problem.ObjValue}") - for v in problem.getVariables(): - print( - f"{v.VariableName} = {v.Value}, ReducedCost = {v.ReducedCost}" - ) - for c in problem.getConstraints(): - print(f"{c.ConstraintName} DualValue = {c.DualValue}") - else: - print(f"Status: {problem.Status.name}") - - -if __name__ == "__main__": - main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/README.md deleted file mode 100644 index 000e7a42..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# LP PDLP Warmstart - -Use warmstart data from a solved LP to solve a similar problem faster. LP only (not MILP). - -**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/model.py deleted file mode 100644 index b0e89311..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/lp_warmstart/model.py +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -""" -PDLP warmstart: solve a similar LP faster by reusing solution context. - -Warmstart is for LP only, not MILP. -""" - -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MAXIMIZE -from cuopt.linear_programming.solver.solver_parameters import ( - CUOPT_METHOD, - CUOPT_PDLP_SOLVER_MODE, -) -from cuopt.linear_programming.solver_settings import ( - SolverSettings, - SolverMethod, - PDLPSolverMode, -) - - -def main(): - print("=== Problem 1 ===") - problem = Problem("LP1") - x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") - y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y") - problem.addConstraint(4 * x + 10 * y <= 130, name="c1") - problem.addConstraint(8 * x - 3 * y >= 40, name="c2") - problem.setObjective(2 * x + y, sense=MAXIMIZE) - - settings = SolverSettings() - settings.set_parameter(CUOPT_METHOD, SolverMethod.PDLP) - settings.set_parameter(CUOPT_PDLP_SOLVER_MODE, PDLPSolverMode.Stable2) - problem.solve(settings) - print(f"Objective: {problem.ObjValue}") - - warmstart_data = problem.getWarmstartData() - print("\n=== Problem 2 (with warmstart) ===") - new_problem = Problem("LP2") - x = new_problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") - y = new_problem.addVariable(lb=0, vtype=CONTINUOUS, name="y") - new_problem.addConstraint(4 * x + 10 * y <= 100, name="c1") - new_problem.addConstraint(8 * x - 3 * y >= 50, name="c2") - new_problem.setObjective(2 * x + y, sense=MAXIMIZE) - settings.set_pdlp_warm_start_data(warmstart_data) - new_problem.solve(settings) - if new_problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"Objective: {new_problem.ObjValue}") - - -if __name__ == "__main__": - main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/README.md deleted file mode 100644 index bcd0f2c3..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Maximization workaround (QP) - -QP supports MINIMIZE only. To maximize f(x), minimize -f(x); then negate the optimal value. - -**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/model.py deleted file mode 100644 index e18aa613..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/maximization_workaround/model.py +++ /dev/null @@ -1,22 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -""" -Maximize -x² + 4x (max at x=2) by minimizing x² - 4x; then report -objective. -""" - -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE - -problem = Problem("MaxWorkaround") - -x = problem.addVariable(lb=0, ub=10, vtype=CONTINUOUS, name="x") -problem.setObjective(x * x - 4 * x, sense=MINIMIZE) - -problem.solve() - -if problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"x = {x.getValue():.4f}") - print(f"Minimized value = {problem.ObjValue:.4f}") - print(f"Original maximum = {-problem.ObjValue:.4f}") -else: - print(f"Status: {problem.Status.name}") diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/README.md deleted file mode 100644 index 45362da0..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Minimal MILP - -Basic mixed-integer program: integer variables with bounds, linear constraints. - -**Problem:** Maximize 5x + 3y subject to 2x + 4y ≥ 230, 3x + 2y ≤ 190, 10 ≤ y ≤ 50, x, y integer. - -- **model.py** — solve and print solution. -- **incumbent_callback.py** — same problem with a callback that prints intermediate (incumbent) solutions during solve. - -**Run:** `python model.py` or `python incumbent_callback.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/incumbent_callback.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/incumbent_callback.py deleted file mode 100644 index 38f553f7..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/incumbent_callback.py +++ /dev/null @@ -1,50 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -""" -Same MILP as model.py but with a callback to receive incumbent (intermediate) solutions. -MILP only; not for LP. -""" - -from cuopt.linear_programming.problem import Problem, INTEGER, MAXIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings -from cuopt.linear_programming.solver.solver_parameters import CUOPT_TIME_LIMIT -from cuopt.linear_programming.internals import GetSolutionCallback - - -class IncumbentCallback(GetSolutionCallback): - def __init__(self, problem, variables, user_data): - super().__init__() - self.problem = problem - self.variables = variables - self.n_callbacks = 0 - self.user_data = user_data - - def get_solution(self, solution, solution_cost, solution_bound, user_data): - self.n_callbacks += 1 - values = self.problem.getIncumbentValues(solution, self.variables) - cost = float(solution_cost[0]) - vals_str = ", ".join(f"{float(v)}" for v in values) - print(f"Incumbent {self.n_callbacks}: [{vals_str}], cost: {cost:.2f}") - - -def main(): - problem = Problem("Incumbent Example") - x = problem.addVariable(vtype=INTEGER) - y = problem.addVariable(vtype=INTEGER) - problem.addConstraint(2 * x + 4 * y >= 230) - problem.addConstraint(3 * x + 2 * y <= 190) - problem.setObjective(5 * x + 3 * y, sense=MAXIMIZE) - - user_data = {"source": "incumbent_callback"} - settings = SolverSettings() - callback = IncumbentCallback(problem, [x, y], user_data) - settings.set_mip_callback(callback, user_data) - settings.set_parameter(CUOPT_TIME_LIMIT, 30) - problem.solve(settings) - - print(f"Status: {problem.Status.name}, Objective: {problem.ObjValue}") - - -if __name__ == "__main__": - main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/model.py deleted file mode 100644 index 5c0bf88e..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_basic/model.py +++ /dev/null @@ -1,36 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -""" -Minimal MILP: integer variables with bounds, linear constraints. - -Problem: - Maximize: 5x + 3y - Subject to: 2x + 4y >= 230, 3x + 2y <= 190, 10 <= y <= 50, x, y integer -""" - -from cuopt.linear_programming.problem import Problem, INTEGER, MAXIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings - - -def main(): - problem = Problem("Simple MIP") - x = problem.addVariable(vtype=INTEGER, name="V_x") - y = problem.addVariable(lb=10, ub=50, vtype=INTEGER, name="V_y") - problem.addConstraint(2 * x + 4 * y >= 230, name="C1") - problem.addConstraint(3 * x + 2 * y <= 190, name="C2") - problem.setObjective(5 * x + 3 * y, sense=MAXIMIZE) - - settings = SolverSettings() - settings.set_parameter("time_limit", 60) - problem.solve(settings) - - if problem.Status.name in ["Optimal", "FeasibleFound"]: - print(f"Objective: {problem.ObjValue}") - print(f"x = {x.getValue()}, y = {y.getValue()}") - else: - print(f"Status: {problem.Status.name}") - - -if __name__ == "__main__": - main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/README.md deleted file mode 100644 index 42a2a1a9..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Production Planning (MILP) - -Two products (A, B), resource limits (machine time, labor, material), minimum production, maximize profit. - -**Run:** `python model.py` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/model.py deleted file mode 100644 index 72ded816..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/milp_production_planning/model.py +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -""" -Production planning: two products, resource limits (machine, labor, material), maximize profit. -""" - -from cuopt.linear_programming.problem import Problem, INTEGER, MAXIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings - - -def main(): - problem = Problem("Production Planning") - x1 = problem.addVariable(lb=10, vtype=INTEGER, name="Product_A") - x2 = problem.addVariable(lb=15, vtype=INTEGER, name="Product_B") - problem.addConstraint(2 * x1 + x2 <= 100, name="Machine_Time") - problem.addConstraint(x1 + 3 * x2 <= 120, name="Labor_Hours") - problem.addConstraint(4 * x1 + 2 * x2 <= 200, name="Material") - problem.setObjective(50 * x1 + 30 * x2, sense=MAXIMIZE) - - settings = SolverSettings() - settings.set_parameter("time_limit", 30) - problem.solve(settings) - - if problem.Status.name in ["Optimal", "FeasibleFound"]: - print(f"Product A: {x1.getValue()}, Product B: {x2.getValue()}") - print(f"Total profit: {problem.ObjValue}") - else: - print(f"Status: {problem.Status.name}") - - -if __name__ == "__main__": - main() diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/README.md deleted file mode 100644 index f18f4f54..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/README.md +++ /dev/null @@ -1,88 +0,0 @@ -# MPS File Solver - -Read and solve LP/MILP problems from standard MPS files using cuOpt. - -## Problem Description - -MPS (Mathematical Programming System) is a standard file format for representing linear and mixed-integer programming problems. This model demonstrates how to: - -1. Load an MPS file using `Problem.readMPS()` (static method) -2. Solve the problem using cuOpt's GPU-accelerated solver -3. Extract and display the solution - -This is useful when you have optimization problems in standard MPS format from other solvers, modeling tools, or benchmark libraries like MIPLIB. - -## MPS File Format - -MPS is a column-oriented format with sections: - -``` -NAME problem_name -ROWS - N OBJ (objective row) - L CON1 (≤ constraint) - G CON2 (≥ constraint) - E CON3 (= constraint) -COLUMNS - X1 OBJ 1.0 - X1 CON1 2.0 - X2 OBJ 2.0 - X2 CON1 3.0 -RHS - RHS CON1 10.0 -BOUNDS - LO BND X1 0.0 - UP BND X1 5.0 -ENDATA -``` - -## Usage - -```bash -# Solve the sample problem -python model.py - -# Solve a custom MPS file -python model.py --file path/to/problem.mps - -# With time limit -python model.py --file problem.mps --time-limit 120 -``` - -## Model Characteristics - -- **Type**: LP or MILP (detected from MPS file) -- **Input**: Standard MPS file format -- **Output**: Solution values, objective, status - -## Sample Problem - -The included `data/air05.mps` is a MIPLIB benchmark (airline crew scheduling): - -- **Variables**: 7,195 (binary) -- **Constraints**: 426 -- **Known optimal**: 26,374 -- **Typical solve time**: ~2 seconds - -## Key API Usage - -```python -from cuopt.linear_programming.problem import Problem -from cuopt.linear_programming.solver_settings import SolverSettings - -# Load MPS file (static method - returns Problem object) -problem = Problem.readMPS("path/to/problem.mps") - -# Configure and solve -settings = SolverSettings() -settings.set_parameter("time_limit", 60) -problem.solve(settings) - -# Check solution -if problem.Status.name in ["Optimal", "FeasibleFound"]: - print(f"Objective: {problem.ObjValue}") -``` - -## Source - -Based on cuOpt's built-in MPS support via `Problem.readMPS()`. diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/README.md deleted file mode 100644 index 67266fee..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# MPS Solver Data - -This directory contains MPS files for testing. - -## Included Files - -### air05.mps (MIPLIB Benchmark) - -An airline crew scheduling problem from the MIPLIB benchmark library. - -| Property | Value | -|----------|-------| -| Type | Binary Integer Program | -| Variables | 7,195 (all binary) | -| Constraints | 426 | -| Non-zeros | 52,121 | -| Known Optimal | 26,374 | - -**Source**: https://miplib.zib.de/instance_details_air05.html - -**Problem**: Given flight legs and possible crew pairings, find the minimum-cost -set of pairings that covers all flight legs (set covering problem). - -## MPS File Format - -MPS (Mathematical Programming System) is a standard format for LP/MILP problems. - -### Sections - -| Section | Purpose | -|---------|---------| -| NAME | Problem name | -| ROWS | Constraint and objective definitions | -| COLUMNS | Variable coefficients in each row | -| RHS | Right-hand side values for constraints | -| BOUNDS | Variable bounds and types | -| ENDATA | End of file marker | - -### Row Types - -| Type | Meaning | -|------|---------| -| N | Objective function (no constraint) | -| L | Less than or equal (≤) | -| G | Greater than or equal (≥) | -| E | Equality (=) | - -### Bound Types - -| Type | Meaning | -|------|---------| -| LO | Lower bound | -| UP | Upper bound | -| FX | Fixed value (lb = ub) | -| FR | Free variable (-∞ to +∞) | -| BV | Binary variable (0 or 1) | -| UI | Upper bound, integer | -| LI | Lower bound, integer | - -## Adding Custom MPS Files - -```bash -python model.py --file path/to/your/problem.mps -``` - -## Standard Test Problem Sources - -- [MIPLIB](https://miplib.zib.de/) - Mixed Integer Programming Library -- [Netlib LP](https://www.netlib.org/lp/) - Classic LP test problems -- [NEOS](https://neos-server.org/neos/) - Network-Enabled Optimization System - -## Creating MPS Files - -cuOpt can export problems to MPS format: - -```python -from cuopt.linear_programming.problem import Problem - -problem = Problem("MyProblem") -# ... define variables, constraints, objective ... -problem.writeMPS("output.mps") -``` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/sample.mps b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/sample.mps deleted file mode 100644 index 6baeb6e5..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/data/sample.mps +++ /dev/null @@ -1,19 +0,0 @@ -NAME PRODUCTION_LP -ROWS - N PROFIT - L RES_A - L RES_B -COLUMNS - PROD_X PROFIT -40.0 - PROD_X RES_A 2.0 - PROD_X RES_B 4.0 - PROD_Y PROFIT -30.0 - PROD_Y RES_A 3.0 - PROD_Y RES_B 2.0 -RHS - RHS1 RES_A 120.0 - RHS1 RES_B 100.0 -BOUNDS - LO BND1 PROD_X 0.0 - LO BND1 PROD_Y 0.0 -ENDATA diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/model.py deleted file mode 100644 index fb8918c1..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/model.py +++ /dev/null @@ -1,283 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -""" -MPS File Solver using cuOpt Python API - -Read and solve LP/MILP problems from standard MPS files using -cuOpt's built-in readMPS method. - -Default benchmark: air05.mps (airline crew scheduling from MIPLIB) -- Best known optimal: 26,374 -""" - -import os -import gzip -import urllib.request -from typing import Optional - -from cuopt.linear_programming.problem import Problem -from cuopt.linear_programming.solver_settings import SolverSettings - - -# MIPLIB benchmark URL -AIR05_URL = "https://miplib.zib.de/WebData/instances/air05.mps.gz" -AIR05_OPTIMAL = 26374 # Best known optimal solution - - -def download_air05(data_dir: str) -> str: - """Download air05.mps from MIPLIB if not present.""" - mps_file = os.path.join(data_dir, "air05.mps") - - if os.path.exists(mps_file): - return mps_file - - os.makedirs(data_dir, exist_ok=True) - gz_file = os.path.join(data_dir, "air05.mps.gz") - - print("Downloading air05.mps from MIPLIB...") - urllib.request.urlretrieve(AIR05_URL, gz_file) - - # Decompress - print("Decompressing...") - with gzip.open(gz_file, "rb") as f_in: - with open(mps_file, "wb") as f_out: - f_out.write(f_in.read()) - - # Clean up - os.remove(gz_file) - print(f"Downloaded: {mps_file}") - - return mps_file - - -def solve_mps( - filepath: str, - time_limit: float = 60.0, - mip_gap: float = 0.01, - verbose: bool = True, -) -> tuple: - """ - Solve an LP/MILP problem from an MPS file. - - Parameters - ---------- - filepath : str - Path to the MPS file - time_limit : float - Solver time limit in seconds - mip_gap : float - MIP relative gap tolerance - verbose : bool - Print solver output - - Returns - ------- - tuple - (problem, solution_dict) or (problem, None) if no solution - """ - - # Read MPS file directly (static method returns Problem object) - problem = Problem.readMPS(filepath) - - print(f"Loaded MPS file: {filepath}") - print(f"Variables: {problem.NumVariables}") - print(f"Constraints: {problem.NumConstraints}") - print(f"Is MIP: {problem.IsMIP}") - - # Solver settings - settings = SolverSettings() - settings.set_parameter("time_limit", time_limit) - settings.set_parameter("log_to_console", verbose) - settings.set_parameter("mip_relative_gap", mip_gap) - - # Solve - print("\nSolving...") - problem.solve(settings) - - # Extract solution - status = problem.Status.name - print(f"\nStatus: {status}") - - if status in ["Optimal", "FeasibleFound", "PrimalFeasible"]: - solution = { - "status": status, - "objective": problem.ObjValue, - "num_variables": problem.NumVariables, - "num_constraints": problem.NumConstraints, - "is_mip": problem.IsMIP, - "mip_gap": mip_gap, - } - - # Get variable values (use getVariables() for MPS-loaded problems) - var_values = {} - try: - variables = problem.getVariables() - for var in variables: - val = var.getValue() - if abs(val) > 1e-6: # Only include non-zero values - var_values[var.Name] = val - except (AttributeError, Exception): - # For MPS problems, variable access may be limited - pass - - solution["variables"] = var_values - return problem, solution - else: - return problem, None - - -def compare_gaps( - filepath: str, - time_limit: float = 120.0, - known_optimal: Optional[float] = None, -) -> dict: - """ - Compare solutions at different MIP gap tolerances. - - Parameters - ---------- - filepath : str - Path to the MPS file - time_limit : float - Solver time limit per run - known_optimal : float, optional - Known optimal objective value. If provided, results include - "gap_to_optimal" (percent above optimal). Omit for generic MPS files. - - Returns - ------- - dict - Results for each gap tolerance - """ - gaps = [0.01, 0.001] # 1% and 0.1% - results = {} - - for gap in gaps: - print(f"\n{'=' * 60}") - print(f"Solving with MIP gap = {gap * 100}%") - print(f"{'=' * 60}") - - problem, solution = solve_mps( - filepath=filepath, time_limit=time_limit, mip_gap=gap, verbose=True - ) - - if solution: - results[gap] = { - "objective": solution["objective"], - "status": solution["status"], - } - if known_optimal is not None: - results[gap]["gap_to_optimal"] = ( - (solution["objective"] - known_optimal) - / known_optimal - * 100 - ) - else: - results[gap] = {"objective": None, "status": "No solution"} - - return results - - -if __name__ == "__main__": - import argparse - - parser = argparse.ArgumentParser(description="Solve LP/MILP from MPS file") - parser.add_argument( - "--file", type=str, default=None, help="Path to MPS file" - ) - parser.add_argument( - "--time-limit", type=float, default=60.0, help="Solver time limit" - ) - parser.add_argument( - "--mip-gap", type=float, default=0.01, help="MIP gap tolerance" - ) - parser.add_argument( - "--compare", action="store_true", help="Compare 1%% vs 0.1%% gap" - ) - parser.add_argument( - "--known-optimal", - type=float, - default=None, - help="Known optimal objective value (enables gap-to-optimal reporting)", - ) - args = parser.parse_args() - - print("=" * 60) - print("MPS File Solver using cuOpt") - print("=" * 60) - - # Determine MPS file to use - script_dir = os.path.dirname(os.path.abspath(__file__)) - data_dir = os.path.join(script_dir, "data") - - if args.file: - mps_file = args.file - else: - # Download air05.mps if not present - mps_file = download_air05(data_dir) - - # Use known optimal only when explicitly set or when using default air05 - known_optimal = args.known_optimal - if known_optimal is None and mps_file.endswith("air05.mps"): - known_optimal = AIR05_OPTIMAL - - if args.compare: - # Compare different gap tolerances - print(f"\nComparing MIP gap tolerances on: {mps_file}") - if known_optimal is not None: - print(f"Best known optimal: {known_optimal}") - - results = compare_gaps( - mps_file, time_limit=args.time_limit, known_optimal=known_optimal - ) - - print() - print("=" * 60) - print("COMPARISON SUMMARY") - print("=" * 60) - if known_optimal is not None: - print(f"Best known optimal: {known_optimal}") - print() - header = f"{'Gap Tolerance':<15} {'Objective':<15}" - if known_optimal is not None: - header += f" {'Gap to Optimal':<15}" - print(header) - print("-" * (45 if known_optimal is None else 60)) - - for gap, result in sorted(results.items()): - if result["objective"] is not None: - line = f"{gap * 100:.1f}%{'':<12} {result['objective']:<15.0f}" - if known_optimal is not None: - line += f" {result['gap_to_optimal']:.2f}%" - print(line) - else: - print(f"{gap * 100:.1f}%{'':<12} {'No solution':<15}") - else: - # Single solve - print(f"\nMPS File: {mps_file}") - print(f"Time Limit: {args.time_limit}s") - print(f"MIP Gap: {args.mip_gap * 100}%") - print() - - problem, solution = solve_mps( - filepath=mps_file, - time_limit=args.time_limit, - mip_gap=args.mip_gap, - verbose=True, - ) - - if solution: - print() - print("=" * 60) - print("SOLUTION") - print("=" * 60) - print(f"Status: {solution['status']}") - print(f"Objective Value: {solution['objective']:.0f}") - if known_optimal is not None: - print(f"Best Known Optimal: {known_optimal}") - print( - f"Gap to Optimal: {(solution['objective'] - known_optimal) / known_optimal * 100:.2f}%" - ) - else: - print("\nNo feasible solution found.") diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/results.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/results.md deleted file mode 100644 index 4100dea6..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/mps_solver/results.md +++ /dev/null @@ -1,90 +0,0 @@ -# MPS Solver Results - -## Problem: air05.mps (MIPLIB benchmark) - -**Description:** Airline crew scheduling - set partitioning problem - -### Problem Characteristics -- **Variables:** 7195 (all binary) -- **Constraints:** 426 -- **Nonzeros:** 52121 -- **Best Known Optimal:** 26374 - ---- - -## Gap Tolerance Comparison - -Comparing different MIP relative gap tolerances to show trade-off between solution quality and solve time. - -### Run Configuration -- **Time Limit:** 60 seconds -- **cuOpt Version:** 26.2.0 -- **Device:** Quadro RTX 8000 (47.24 GiB VRAM) -- **CPU:** AMD Ryzen Threadripper PRO 3975WX (32 cores) - -### Results Summary - -| Gap Tolerance | Objective | Gap to Optimal | Solve Time | Nodes Explored | -|--------------|-----------|----------------|------------|----------------| -| 0.1% | **26374** | 0.00% | 8.42s | 386 | -| 1.0% | 26491 | 0.44% | 3.23s | 328 | - -### Key Observations - -1. **Tighter gap finds optimal**: The 0.1% gap tolerance found the exact best-known optimal solution (26374) -2. **Trade-off**: The looser 1.0% gap converged faster (3.2s vs 8.4s) but with 0.44% suboptimality -3. **Both are fast**: cuOpt solved this 7195-variable MILP in under 10 seconds - ---- - -## Detailed Solver Output (0.1% gap) - -``` -Solving a problem with 426 constraints, 7195 variables (7195 integers), and 52121 nonzeros - -Presolve removed: 90 constraints, 1116 variables, 16171 nonzeros -Presolved problem: 336 constraints, 6079 variables, 35950 nonzeros - -Root relaxation objective +2.58776093e+04 - -Strong branching using 7 threads and 222 fractional variables -Explored 386 nodes in 7.73s. - -Optimal solution found within relative MIP gap tolerance (1.0e-03) -Solution objective: 26374.000000 -relative_mip_gap 0.000992 -total_solve_time 8.421934 -``` - ---- - -## Detailed Solver Output (1.0% gap) - -``` -Solving a problem with 426 constraints, 7195 variables (7195 integers), and 52121 nonzeros - -Presolve removed: 90 constraints, 1116 variables, 16171 nonzeros -Presolved problem: 336 constraints, 6079 variables, 35950 nonzeros - -Root relaxation objective +2.58776093e+04 - -Strong branching using 63 threads and 222 fractional variables -Explored 328 nodes in 1.09s. - -Optimal solution found within relative MIP gap tolerance (1.0e-02) -Solution objective: 26491.000000 -relative_mip_gap 0.009669 -total_solve_time 3.233650 -``` - ---- - -## Usage - -```bash -# Default: download air05.mps and solve with comparison -python model.py --compare --time-limit 60 - -# Solve custom MPS file -python model.py --file path/to/problem.mps --time-limit 300 --mip-gap 0.001 -``` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/README.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/README.md deleted file mode 100644 index cf2173a4..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Portfolio optimization (QP) - -Minimize portfolio variance (risk) subject to fully invested (sum x = 1) and minimum return. Three assets; Q must be PSD. - -**Run:** `python model.py` - -**Note:** QP is beta; objective must be MINIMIZE. diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/model.py b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/model.py deleted file mode 100644 index 0196efdc..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/assets/portfolio/model.py +++ /dev/null @@ -1,49 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 - -""" -Portfolio: minimize variance x'Qx subject to sum(x)=1, r'x >= target, x >= 0. -QP is beta; MUST use MINIMIZE. -""" - -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings - -problem = Problem("Portfolio") - -x1 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_a") -x2 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_b") -x3 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_c") - -r1, r2, r3 = 0.12, 0.08, 0.05 -target_return = 0.08 - -problem.setObjective( - 0.04 * x1 * x1 - + 0.02 * x2 * x2 - + 0.01 * x3 * x3 - + 0.02 * x1 * x2 - + 0.01 * x1 * x3 - + 0.016 * x2 * x3, - sense=MINIMIZE, -) -problem.addConstraint(x1 + x2 + x3 == 1, name="budget") -problem.addConstraint( - r1 * x1 + r2 * x2 + r3 * x3 >= target_return, name="min_return" -) - -settings = SolverSettings() -settings.set_parameter("time_limit", 60) -problem.solve(settings) - -if problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"Portfolio variance: {problem.ObjValue:.6f}") - print(f"Std dev: {problem.ObjValue**0.5:.4f}") - print(f" Stock A: {x1.getValue() * 100:.2f}%") - print(f" Stock B: {x2.getValue() * 100:.2f}%") - print(f" Stock C: {x3.getValue() * 100:.2f}%") - print( - f"Expected return: {(r1 * x1.getValue() + r2 * x2.getValue() + r3 * x3.getValue()) * 100:.2f}%" - ) -else: - print(f"Status: {problem.Status.name}") diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/SOURCES.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/SOURCES.md deleted file mode 100644 index f258683e..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/SOURCES.md +++ /dev/null @@ -1,40 +0,0 @@ -# Sources - -Eval prompts in `evals.json` for the `cuopt-numerical-optimization-api-python` skill are -adapted from the **OptiGuide / OptiMind IndustryOR** dataset: - -- Repository: [microsoft/OptiGuide](https://github.com/microsoft/OptiGuide) -- File: [`optimind/data/optimind_cleaned_classified_industryor.csv`](https://github.com/microsoft/OptiGuide/blob/main/optimind/data/optimind_cleaned_classified_industryor.csv) -- License: MIT (Copyright (c) Microsoft Corporation) - -Each entry's `source` field references the original row index. Problem -statements are quoted verbatim; ground-truth values are the dataset's -optimal objective values. - -## License - -The MIT license under which the source dataset is distributed: - -``` -MIT License - -Copyright (c) Microsoft Corporation. - -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 -``` diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/evals.json b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/evals.json deleted file mode 100644 index 57ff74c6..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/evals/evals.json +++ /dev/null @@ -1,1091 +0,0 @@ -[ - { - "id": "lpmilp-001-production-planning-problem", - "question": "A factory produces two types of food, I and II, and currently has 50 skilled workers. It is known that one skilled worker can produce $10 \\ \\mathrm{kg} / \\ \\mathrm{h}$ of food I or $6 \\ \\mathrm{kg} / \\ \\mathrm{h}$ of food II. According to contract bookings, the weekly demand for these two foods will rise sharply, as shown in Table 1-11. Therefore, the factory has decided to train 50 new workers by the end of the 8th week. It is known that a worker works $40 \\ \\mathrm{h}$ per week, and a skilled worker can train up to three new workers in two weeks (during the training period, both the skilled worker and the trainees do not participate in production). The weekly wage of a skilled worker is 360 yuan, the weekly wage of a trainee during the training period is 120 yuan, and after training, the wage is 240 yuan per week, with the same production efficiency as skilled workers. During the transition period of training, many skilled workers are willing to work overtime, and the factory has decided to arrange some workers to work $60 \\ \\mathrm{h}$ per week, with a weekly wage of 540 yuan. If the booked food cannot be delivered on time, the compensation fee for each week of delay per $ \\ \\mathrm{kg}$ is 0.5 yuan for food I and 0.6 yuan for food II. Under these conditions, how should the factory make comprehensive arrangements to minimize the total cost?\n\nTable 1-11\n\n| Week | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |\n|------|---|---|---|---|---|---|---|---|\n| I | 10000 | 10000 | 12000 | 12000 | 16000 | 16000 | 20000 | 20000 |\n| II | 6000 | 7200 | 8400 | 10800 | 10800 | 12000 | 12000 | 12000 |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "219816.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 0 (MIT)" - }, - { - "id": "lpmilp-002-capacitated-lot-sizing-problem-c", - "question": "Each year $t=1,\\dots ,n$ two production lines deliver $a_1=10$ and $a_2=15$ new fighter jets (25 total). $n=10$. Decide how many of that year's 25 aircraft, $x_t$, enter combat immediately and how many, $y_t=25-x_t$, become training platforms. A training jet produces five newly qualified pilots who are available at the start of the next year; every combat jet must be matched with one trained pilot to be operational, and training jets can be reassigned to combat in later years. Starting with no aircraft or pilots, choose integer sequences $\\{x_t,y_t\\}_{t=1}^n$ to maximise the cumulative number of operational combat jet-years $\\sum_{t=1}^{n} x_t$, subject to annual pilot-availability and fleet-balance constraints.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "1350.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 1 (MIT)" - }, - { - "id": "lpmilp-003-capacitated-lot-sizing-problem-c", - "question": "A company specializing in foldable tables needs to create an optimal production and human resources plan for a six-month period (January to June) to maximize its total net profit. The plan must detail monthly in-house production levels, outsourcing quantities, and workforce management (hiring/firing).\n\n**Initial Conditions (at the start of January):**\n- Initial Workforce: 1,000 employees\n- Initial Inventory: 15,000 units\n\n**Revenue and Cost Structure:**\n- **Sales Price:** 300 Yuan per unit sold.\n- **Raw Material Cost:** 90 Yuan per unit, applicable *only* to units produced in-house.\n- **Outsourcing Cost:** 200 Yuan per unit for finished tables acquired from a third-party supplier. This is an all-inclusive cost.\n- **Inventory Holding Cost:** 15 Yuan per unit for any inventory held at the end of a month.\n- **Backorder Cost:** 35 Yuan per unit for any unfulfilled demand (stockout) carried over to the next month.\n\n**Labor and Production Parameters:**\n- **Labor Requirement:** Each in-house unit requires 5 labor hours to produce.\n- **Regular Labor:** Each worker provides 160 regular working hours per month (8 hours/day * 20 days/month). The company pays a regular wage of 30 Yuan/hour for these 160 hours, regardless of full utilization.\n- **Overtime Labor:** Workers can perform overtime. Total overtime hours per month for the entire workforce cannot exceed 20 hours per worker. The overtime wage is 40 Yuan/hour.\n- **Workforce Management:** The company can hire or fire workers each month. The cost to hire a new worker is 5,000 Yuan, and the cost to fire a worker is 8,000 Yuan.\n\n**Demand and Fulfillment Logic:**\n- Unfulfilled demand from one month is back-ordered and must be met in subsequent months.\n- The company fulfills orders (both current demand and backorders) using available inventory from the previous month, current in-house production, and outsourced units.\n\n**Terminal Condition (at the end of June):**\n- The ending inventory must be at least 10,000 units.\n- All backorders must be cleared (i.e., ending backorders must be zero).\n\n**Forecasted Demand:**\n| Month | January | February | March | April | May | June |\n|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n| Demand Forecast | 20,000 | 40,000 | 42,000 | 35,000 | 19,000 | 18,500 |\n\nBased on this information, formulate the optimal six-month operational plan.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "10349920.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 2 (MIT)" - }, - { - "id": "lpmilp-004-farm-planning", - "question": "A farmer needs to decide how many cows, sheep, and chickens to raise in order to achieve maximum profit. The farmer can sell cows, sheep, and chickens for $500, $200, and $8 each, respectively. The feed costs for each cow, sheep, and chicken are $100, $80, and $5, respectively. The profit is the difference between the selling price and the feed cost. Each cow, sheep, and chicken produces 10, 5, and 3 units of manure per day, respectively. Due to the limited time the farm staff has for cleaning the farm each day, they can handle up to 800 units of manure. Additionally, because of the limited farm size, the farmer can raise at most 50 chickens. Furthermore, the farmer must have at least 10 cows to meet customer demand. The farmer must also raise at least 20 sheep. Finally, the total number of animals cannot exceed 100.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "30400.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 3 (MIT)" - }, - { - "id": "lpmilp-005-diet-problem", - "question": "Mary is planning her dinner tonight. Every 100 grams of okra contains 3.2 grams of fiber, every 100 grams of carrots contains 2.7 grams of fiber, every 100 grams of celery contains 1.6 grams of fiber, and every 100 grams of cabbage contains 2 grams of fiber. How many grams of each type of food should Mary buy to maximize her fiber intake?\n\nShe is considering choosing one among salmon, beef, and pork as a protein source. For the chosen protein she must take at least one gram of it.\n\nShe also considers choosing at least two kinds of vegetables among okra, carrots, celery, and cabbage. For each of the selected vegetables, she must take at least one gram.\n\nThe price of salmon is $4 per 100 grams, beef is $3.6 per 100 grams, pork is $1.8 per 100 grams. The price of okra is $2.6 per 100 grams, carrots are $1.2 per 100 grams, celery is $1.6 per 100 grams, and cabbage is $2.3 per 100 grams. Mary has a budget of $15 for this meal.\n\nThe total food intake should be 600 grams.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "18.95657143", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 4 (MIT)" - }, - { - "id": "lpmilp-006-capacitated-lot-sizing-problem-c", - "question": "The contract reservations for the next year for products I, II, and III of a certain factory in each quarter are shown in Table 1-10.\n\nTable 1-10\n| Product | 1 | 2 | 3 | 4 |\n|---------|------|------|------|------|\n| I | 1500 | 1000 | 2000 | 1200 |\n| II | 1500 | 1500 | 1200 | 1500 |\n| III | 1000 | 2000 | 1500 | 2500 |\n\nAt the beginning of the first quarter, there is no inventory for these three products, and it is required to have 150 units in stock for each product by the end of the fourth quarter. It is known that the factory has 15,000 production hours per quarter, and each unit of products I, II, and III requires 2, 4, and 3 hours respectively. Due to a change in equipment, product I cannot be produced in the second quarter. It is stipulated that if the products cannot be delivered on time, a compensation of 20 yuan per unit per quarter delay is required for products I and II, while for product III, the compensation is 10 yuan. Additionally, for products produced but not delivered in the current quarter, the inventory cost is 5 yuan per unit per quarter. How should the factory schedule production to minimize the total cost of compensation and inventory?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "10755.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 5 (MIT)" - }, - { - "id": "lpmilp-007-transportation-problem", - "question": "An Italian transportation company needs to move some empty containers from its 6 warehouses (located in Verona, Perugia, Rome, Pescara, Taranto, and Lamezia) to major national ports (Genoa, Venice, Ancona, Naples, Bari). The container inventory at the warehouses is as follows:\n\n| | Empty Containers |\n|:---:|:---:|\n| Verona | 10 |\n| Perugia | 12 |\n| Rome | 20 |\n| Pescara | 24 |\n| Taranto | 18 |\n| Lamezia | 40 |\n\nThe demand at the ports is as follows:\n\n| | Container Demand |\n|:---:|:---:|\n| Genoa | 20 |\n| Venice | 15 |\n| Ancona | 25 |\n| Naples | 33 |\n| Bari | 21 |\n\nThe transport is carried out by a fleet of trucks. The cost to transport each container is proportional to the distance traveled by the trucks, with a rate of 30 euros per kilometer. Each truck can carry up to 2 containers. The distances are as follows:\n\n| | Genoa | Venice | Ancona | Naples | Bari |\n|:---:|:---:|:---:|:---:|:---:|:---:|\n| Verona | $290 \\mathrm{~km}$ | $115 \\mathrm{~km}$ | $355 \\mathrm{~km}$ | $715 \\mathrm{~km}$ | $810 \\mathrm{~km}$ |\n| Perugia | $380 \\mathrm{~km}$ | $340 \\mathrm{~km}$ | $165 \\mathrm{~km}$ | $380 \\mathrm{~km}$ | $610 \\mathrm{~km}$ |\n| Rome | $505 \\mathrm{~km}$ | $530 \\mathrm{~km}$ | $285 \\mathrm{~km}$ | $220 \\mathrm{~km}$ | $450 \\mathrm{~km}$ |\n| Pescara | $655 \\mathrm{~km}$ | $450 \\mathrm{~km}$ | $155 \\mathrm{~km}$ | $240 \\mathrm{~km}$ | $315 \\mathrm{~km}$ |\n| Taranto | $1010 \\mathrm{~km}$ | $840 \\mathrm{~km}$ | $550 \\mathrm{~km}$ | $305 \\mathrm{~km}$ | $95 \\mathrm{~km}$ |\n| Lamezia | $1072 \\mathrm{~km}$ | $1097 \\mathrm{~km}$ | $747 \\mathrm{~km}$ | $372 \\mathrm{~km}$ | $333 \\mathrm{~km}$ |\n\nWrite a mathematical program to find the minimum cost transportation policy and solve it.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "904590.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 6 (MIT)" - }, - { - "id": "lpmilp-008-assignment-problem", - "question": "Now, we need to determine 4 out of 5 workers to complete one of the four tasks respectively. Due to each worker's different technical specialties, the time required for them to complete each task varies. The hours required by each worker to complete each task are shown in Table 5-2.\n\nTable 5-2\n| Worker | $A$ | $B$ | $C$ | $D$ |\n|--------|-----|-----|-----|-----|\n| I | 9 | 4 | 3 | 7 |\n| II | 4 | 6 | 5 | 6 |\n| III | 5 | 4 | 7 | 5 |\n| IV | 7 | 5 | 2 | 3 |\n| V | 10 | 6 | 7 | 4 |\n\nTry to find a job assignment plan that minimizes the total working hours.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "14.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 7 (MIT)" - }, - { - "id": "lpmilp-009-profit-maximization-problem", - "question": "Haus Toys can manufacture and sell toy trucks, toy airplanes, toy boats, and toy trains. The profit for each truck sold is $5, each airplane $10, each boat $8, and each train $7. How many types of toys should Haus Toys manufacture to maximize profits?\n\nThere are 890 units of wood available. Each truck requires 12 units, each airplane 20 units, each boat 15 units, and each train 10 units.\n\nThere are 500 units of steel available. Each airplane requires 3 units, each boat 5 units, each train 4 units, and each truck 6 units.\n\nIf Haus Toys manufactures trucks, they will not manufacture trains.\n\nHowever, if they manufacture boats, they will also manufacture airplanes.\n\nThe number of toy boats manufactured cannot exceed the number of toy trains manufactured.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "623.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 8 (MIT)" - }, - { - "id": "lpmilp-010-set-cover", - "question": "A convenience supermarket is planning to open several chain stores in a newly built residential area in the northwest suburb of the city. For shopping convenience, the distance from any residential area to one of the chain stores should not exceed $800 \\mathrm{~m}$. Table 5-1 shows the new residential areas and the residential areas within a radius of $800 \\mathrm{~m}$ from each of them. Question: What is the minimum number of chain stores the supermarket needs to build among the mentioned residential areas, and in which residential areas should they be built?\n\n| Area Code | Residential Areas within $800 \\mathrm{~m}$ Radius |\n|-----------|---------------------------------------------------|\n| A | A, C, E, G, H, I |\n| B | B, H, I |\n| C | A, C, G, H, I |\n| D | D, J |\n| E | A, E, G |\n| F | F, J, K |\n| G | A, C, E, G |\n| H | A, B, C, H, I |\n| I | A, B, C, H, I |\n| J | D, F, J, K, L |\n| K | F, J, K, L |\n| L | J, K, L |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "3.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 9 (MIT)" - }, - { - "id": "lpmilp-011-production-planning-problem", - "question": "A company produces two types of small motorcycles, where type A is entirely manufactured by the company, and type B is assembled from imported parts. The production, assembly, and inspection time required for each unit of these two products are shown in Table 3.2.\n\nTable 3.2\n\n| Type | Process | | | Selling Price
(Yuan/unit) |\n| :---: | :---: | :---: | :---: | :---: |\n| | Manufacturing | Assembly | Inspection | |\n| Type A (hours/unit) | 20 | 5 | 3 | 650 |\n| Type B (hours/unit) | 0 | 7 | 6 | 725 |\n| Max production capacity per week (hours) | 120 | 80 | 40 | |\n| Production cost per hour (Yuan) | 12 | 8 | 10 | |\n\nIf the company's operational goals and targets are as follows:\n\n$p_{1}$ : The total profit per week should be at least 3000 yuan;\n\n$p_{2}$ : At least 5 units of type A motorcycles should be produced per week;\n\n$p_{3}$ : Minimize the idle time of each process as much as possible. The weight coefficients of the three processes are their hourly costs, and overtime is not allowed.\n\nTry to establish a model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "272.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 10 (MIT)" - }, - { - "id": "lpmilp-012-facility-location-problem", - "question": "Red Star Plastics Factory produces six distinct types of plastic containers. Each container type is characterized by a specific volume, market demand, and unit variable production cost, as detailed in Table 5-11.\n\n**Table 5-11: Container Data**\n| Container Type (Code) | 1 | 2 | 3 | 4 | 5 | 6 |\n| :------------------------------ | :--- | :--- | :--- | :--- | :--- | :---- |\n| Volume ($\\text{cm}^3$) | 1500 | 2500 | 4000 | 6000 | 9000 | 12000 |\n| Market Demand (units) | 500 | 550 | 700 | 900 | 400 | 300 |\n| Unit Variable Production Cost (Yuan/unit) | 5 | 8 | 10 | 12 | 16 | 18 |\n\nThe production of any container type necessitates the use of its dedicated specialized equipment. If the decision is made to **activate** the production equipment for a particular container type (i.e., if the production quantity of that type is greater than zero), a fixed setup cost of 1200 Yuan is incurred for that specific equipment.\n\nShould the production quantity of a certain container type be insufficient to meet its direct demand, the factory has the option to utilize other container types with **larger or equal volume** as substitutes to fulfill this unmet demand. For instance, type 2 containers (volume 2500 $\\text{cm}^3$) can be used to satisfy the demand for type 1 containers (requiring a volume of 1500 $\\text{cm}^3$), but type 1 containers cannot be used for type 2 demand. In this problem, the container type codes are pre-sorted in ascending order of their volumes.\n\n**Question:**\nHow should the factory organize its production? The objective is to develop a production plan that minimizes the total cost—comprising the sum of variable production costs for all containers produced and the fixed costs for all activated equipment—while ensuring that the demand for all container types is fully met.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "43200.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 11 (MIT)" - }, - { - "id": "lpmilp-013-profit-maximization-problem", - "question": "Tom and Jerry just bought a farm in Sunshine Valley, and they are considering using it to plant corn, wheat, soybeans, and sorghum. The profit per acre for planting corn is $1500, the profit per acre for planting wheat is $1200, the profit per acre for planting soybeans is $1800, and the profit per acre for planting sorghum is $1600. To maximize their profit, how many acres of land should they allocate to each crop? Tom and Jerry’s farm has a total area of 100 acres.\n\nThe land area used for planting corn must be at least twice the land area used for planting wheat.\n\nThe land area used for planting soybeans must be at least half the land area used for planting sorghum.\n\nThe land area used for planting wheat must be three times the land area used for planting sorghum.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "180000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 12 (MIT)" - }, - { - "id": "lpmilp-014-knapsack", - "question": "Mary is planning tonight's dinner. She wants to choose a combination of protein and vegetables to maximize her protein intake for the meal. Her protein options are chicken, salmon, and tofu, which can be bought in any quantity.\n\n- Chicken: 23g protein, $3.00 cost, per 100g.\n- Salmon: 20g protein, $5.00 cost, per 100g.\n- Tofu: 8g protein, $1.50 cost, per 100g.\n\nShe also wants to choose from a list of five vegetables, sold in 100g packs. She must select at least three different types of vegetables.\n\n- Broccoli (100g pack): 2.8g protein, $1.20 cost.\n- Carrots (100g pack): 0.9g protein, $0.80 cost.\n- Spinach (100g pack): 2.9g protein, $1.50 cost.\n- Bell Pepper (100g pack): 1.0g protein, $1.00 cost.\n- Mushrooms (100g pack): 3.1g protein, $2.00 cost.\n\nMary has two main constraints:\n1. Her total budget is $20.\n2. The total weight of all food must not exceed 800 grams.\n\nHow should Mary choose her ingredients to get the maximum possible amount of protein?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "123.8", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 13 (MIT)" - }, - { - "id": "lpmilp-015-lot-sizing-problem", - "question": "A certain factory needs to use a special tool over $n$ planning stages. At stage $j$, $r_j$ specialized tools are needed. At the end of this stage, all tools used within this stage must be sent for repair before they can be reused. There are two repair methods: one is slow repair, which is cheaper (costs $b$ per tool) but takes longer ($p$ stages to return, e.g. if a tool goes to repair after stage 1, it will return at stage 1+p); the other is fast repair, which costs $c$ per tool $(c > b)$ and is faster, requiring only $q$ stages to return $(q < p)$. If the repaired tools cannot meet the needs, new ones must be purchased, with a cost of $a$ per new tool $(a > c)$. This special tool will no longer be used after $n$ stages. Determine an optimal plan for purchasing and repairing the tools to minimize the cost spent on tools during the planning period.\\n\\nn = 10 # number of stages\\nr = [3, 5, 2, 4, 6, 5, 4, 3, 2, 1] # tool requirements per stage, indexing starts at 1\\na = 10 # cost of buying a new tool\\nb = 1 # cost of slow repair\\nc = 3 # cost of fast repair\\np = 3 # slow repair duration\\nq = 1 # fast repair duration", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "134.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 14 (MIT)" - }, - { - "id": "lpmilp-016-lot-sizing-problem", - "question": "A store plans to formulate the purchasing and sales plan for a certain product for the first quarter of next year. It is known that the warehouse capacity of the store can store up to 500 units of the product, and there are 200 units in stock at the end of this year. The store purchases goods once at the beginning of each month. The purchasing and selling prices of the product in each month are shown in Table 1.3.\n\nTable 1.3\n\n| Month | 1 | 2 | 3 |\n| :---: | :---: | :---: | :---: |\n| Purchasing Price (Yuan) | 8 | 6 | 9 |\n| Selling Price (Yuan) | 9 | 8 | 10 |\n\nNow, determine how many units should be purchased and sold each month to maximize the total profit, and express this problem as a linear programming model.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "4100.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 15 (MIT)" - }, - { - "id": "lpmilp-017-production-planning-problem", - "question": "A textile factory produces two types of fabrics: one for clothing and the other for curtains. The factory operates two shifts, with a weekly production time set at 110 hours. Both types of fabrics are produced at a rate of 1000 meters per hour. Assuming that up to 70,000 meters of curtain fabric can be sold per week, with a profit of 2.5 yuan per meter, and up to 45,000 meters of clothing fabric can be sold per week, with a profit of 1.5 yuan per meter, the factory has the following objectives in formulating its production plan:\n\n$p_{1}$ : The weekly production time must fully utilize 110 hours;\n\n$p_{2}$ : Overtime should not exceed 10 hours per week;\n\n$p_{3}$ : At least 70,000 meters of curtain fabric and 45,000 meters of clothing fabric must be sold per week;\n\n$p_{4}$ : Minimize overtime as much as possible.\n\nFormulate a model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "5.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 16 (MIT)" - }, - { - "id": "lpmilp-018-production-planning-problem", - "question": "A furniture store can choose to order chairs from three different manufacturers: A, B, and C. The cost of ordering each chair from manufacturer A is $50, from manufacturer B is $45, and from manufacturer C is $40. The store needs to minimize the total cost of the order.\n\nAdditionally, each order from manufacturer A will include 15 chairs, while each order from manufacturers B and C will include 10 chairs. The number of orders must be an integer. The store needs to order at least 100 chairs.\n\nEach order from manufacturer A will include 15 chairs, while each order from manufacturers B and C will include 10 chairs. The store needs to order at most 500 chairs.\n\nIf the store decides to order chairs from manufacturer A, it must also order at least 10 chairs from manufacturer B.\n\nFurthermore, if the store decides to order chairs from manufacturer B, it must also order chairs from manufacturer C.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "4000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 17 (MIT)" - }, - { - "id": "lpmilp-019-production-planning-problem", - "question": "Bright Future Toys wants to build and sell robots, model cars, building blocks, and dolls. The profit for each robot sold is $15, for each model car sold is $8, for each set of building blocks sold is $12, and for each doll sold is $5. How many types of toys should Bright Future Toys manufacture to maximize profit?\nThere are 1200 units of plastic available. Each robot requires 30 units of plastic, each model car requires 10 units of plastic, each set of building blocks requires 20 units of plastic, and each doll requires 15 units of plastic.\n\nThere are 800 units of electronic components available. Each robot requires 8 units of electronic components, each model car requires 5 units of electronic components, each set of building blocks requires 3 units of electronic components, and each doll requires 2 units of electronic components.\n\nIf Bright Future Toys manufactures robots, they will not manufacture dolls.\n\nHowever, if they manufacture model cars, they will also manufacture building blocks.\n\nThe number of dolls manufactured cannot exceed the number of model cars manufactured.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "956.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 18 (MIT)" - }, - { - "id": "lpmilp-020-lot-sizing-problem", - "question": "A restaurant needs to order dining tables from three different suppliers, A, B, and C. The cost of ordering each dining table from Supplier A is $120, from Supplier B is $110, and from Supplier C is $100. The restaurant needs to minimize the total cost of the order.\n\nAdditionally, each order from Supplier A will include 20 tables, while each order from Suppliers B and C will include 15 tables. The number of orders must be an integer. The restaurant needs to order at least 150 tables.\n\nEach order from Supplier A will include 20 tables, and each order from Suppliers B and C will include 15 tables. The restaurant needs to order no more than 600 tables.\n\nIf the restaurant decides to order tables from Supplier A, it must also order at least 30 tables from Supplier B.\n\nAdditionally, if the restaurant decides to order tables from Supplier B, it must also order tables from Supplier C.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "15000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 19 (MIT)" - }, - { - "id": "lpmilp-021-production-planning-problem", - "question": "A company plans to produce 3 types of products $A_{1}, A_{2}, A_{3}$. It can produce for 22 days in a month. The following table gives the maximum demand (unit $=100 \\mathrm{~kg}$), price ($\\$ / 100 \\mathrm{Kg}$), production cost (per 100Kg product), and production quota (the maximum number of 100kg units that can be produced in one day if all production lines are devoted to this product).\n\n| Product | $A_{1}$ | $A_{2}$ | $A_{3}$ |\n| :---: | :---: | :---: | :---: |\n| Maximum Demand | 5300 | 4500 | 5400 |\n| Selling Price | $124$ | $109$ | $115$ |\n| Production Cost | $73.30$ | $52.90$ | $65.40$ |\n| Production Quota | 500 | 450 | 550 |\n\nThe fixed activation cost of the production line is as follows:\n\n| Product | $A_{1}$ | $A_{2}$ | $A_{3}$ |\n| :---: | :---: | :---: | :---: |\n| Activation Cost | $170000$ | $150000$ | $100000$ |\n\nMinimum production batch:\n\n$$\n\\begin{array}{c|ccc}\nProduct & A_{1} & A_{2} & A_{3} \\\\\n\\hline\nMinimum Batch & 20 & 20 & 16\n\\end{array}\n$$\n\nPlease formulate an operations research model to determine a production plan that maximizes total revenue while accommodating fixed activation costs and minimum production batch constraints.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "270290.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 20 (MIT)" - }, - { - "id": "lpmilp-022-profit-maximization-problem", - "question": "Hongdou Clothing Factory uses three special equipment to produce shirts, short-sleeved shirts, and casual clothes respectively. It is known that the labor, material usage, selling price, and variable cost of each of the above products are as shown in Table 5-10.\n\nTable 5-10\n\n| Product Name | Labor per unit | Material per unit | Selling Price | Variable Cost |\n|--------------|----------------|------------------|---------------|---------------|\n| Shirt | 3 | 4 | 120 | 60 |\n| Short-sleeve | 2 | 3 | 80 | 40 |\n| Casual Cloth | 6 | 6 | 180 | 80 |\n\nIt is known that the available labor per week is 1500 units, the available material is 1600 units, and the weekly fixed costs for the three special equipment for producing shirts, short-sleeved shirts, and casual clothes are 2000, 1500, and 1000 respectively. Design a weekly production plan for the factory to maximize its profit.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "24000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 21 (MIT)" - }, - { - "id": "lpmilp-023-transportation-problem", - "question": "A manufacturing company needs to transport 1800 units of product from the warehouse to three different sales points. The company has four transportation options to choose from: truck, van, motorcycle, and electric vehicle. Since the van and electric vehicle both consume a lot of energy, the company wants to choose only one of these two options. Each trip with a truck generates 100 units of pollution, a van generates 50 units of pollution, a motorcycle generates 10 units of pollution, and an electric vehicle generates 0 units of pollution. The total pollution generated from all trips cannot exceed 2000 units. At least 10 trips must use a truck. Trucks, vans, motorcycles, and electric vehicles can transport 100 units, 80 units, 40 units, and 60 units of product per trip, respectively. The company needs to ensure that the total amount of transported product is at least 1800 units. Return the minimized pollution in units while meeting all constraints.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "1000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 22 (MIT)" - }, - { - "id": "lpmilp-024-portfoliooptimization", - "question": "An investor plans to invest 100,000 yuan, with two investment options to choose from. The first investment guarantees a return of 0.7 yuan for every 1 yuan invested after one year. The second investment guarantees a return of 2 yuan for every 1 yuan invested after two years, but the investment time must be in multiples of two years. In order to maximize the investor's earnings by the end of the third year, how should the investments be made? Formulate this as a linear programming problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "510000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 23 (MIT)" - }, - { - "id": "lpmilp-025-set-multi-cover", - "question": "The number of salespeople required at a 24-hour convenience store in different time periods is as follows: 2:00-6:00 - 10 people, 6:00-10:00 - 15 people, 10:00-14:00 - 25 people, 14:00-18:00 - 20 people, 18:00-22:00 - 18 people, 22:00-2:00 - 12 people. Salespeople start their shifts at 2:00, 6:00, 10:00, 14:00, 18:00, and 22:00, working continuously for 8 hours. Determine the minimum number of salespeople needed to meet the requirements.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "53.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 24 (MIT)" - }, - { - "id": "lpmilp-026-factory-planning-problem", - "question": "A factory produces three types of products: I, II, and III. Each product needs to go through two processing procedures, A and B. The factory has two pieces of equipment that can complete process A, denoted as A1 and A2; it has three pieces of equipment that complete process B, denoted as B1, B2, and B3. Product I can be processed on any equipment for A and B; Product II can be processed on any A equipment but only on B1 for process B; Product III can only be processed on A2 and B2. Given the unit processing time on various machines, raw material costs, product sale prices, effective machine hours, and the costs of operating the machines at full capacity as shown in Table 1-4, the task is to arrange the optimal production plan to maximize the factory's profit.\n\nTable 1-4\n| Equipment | Product I | Product II | Product III | Effective Machine Hours | Operating Costs at Full Capacity (Yuan) |\n|------------|-----------|------------|-------------|--------------------------|------------------------------------------|\n| A1 | 5 | 10 | | 6000 | 300 |\n| A2 | 7 | 9 | 12 | 10000 | 321 |\n| B1 | 6 | 8 | | 4000 | 250 |\n| B2 | 4 | | 11 | 7000 | 783 |\n| B3 | 7 | | | 4000 | 200 |\n| Raw Material Cost (Yuan/Unit) | 0.25 | 0.35 | 0.50 | | |\n| Unit Price (Yuan/Unit) | 1.25 | 2.00 | 2.80 | | |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "1146.4142", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 25 (MIT)" - }, - { - "id": "lpmilp-027-profit-maximization-problem", - "question": "Someone has a fund of 300,000 yuan and has the following investment projects in the next three years:\n(1) Investment can be made at the beginning of each year within three years, with an annual profit of 20% of the investment amount, and the principal and interest can be used for investment in the following year;\n(2) Investment is only allowed at the beginning of the first year, and it can be recovered at the end of the second year, with the total principal and interest amounting to 150% of the investment amount, but the investment limit is no more than 150,000 yuan;\n(3) Investment is allowed at the beginning of the second year within three years, and it can be recovered at the end of the third year, with the total principal and interest amounting to 160% of the investment amount, and the investment limit is 200,000 yuan;\n(4) Investment is allowed at the beginning of the third year within three years, and it can be recovered in one year with a profit of 40%, and the investment limit is 100,000 yuan.\nChapter One: Linear Programming and Simplex Method\nTry to determine an investment plan for this person that maximizes the principal and interest at the end of the third year.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "580000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 26 (MIT)" - }, - { - "id": "lpmilp-028-assignment-problem", - "question": "Jieli Company needs to recruit three types of professionals to work in the two regional branches located in Donghai City and Nanjiang City. The demand for different professionals in these regional branches is shown in Table 4-3. After assessing the situation of the applicants, the company has categorized them into 6 types. Table 4-4 lists the specialties each type of person can handle, the specialty they prefer, and the city they prefer to work in. The company's personnel arrangement considers the following three priorities:\n$p_1$: All three types of professionals needed are fully met;\n$p_2$: 4000 recruited personnel meet their preferred specialty;\n$p_3$: 4000 recruited personnel meet their preferred city.\nFormulate a plan to minimize the total number of people that need to move from one city to another to meet these priorities. Return the minimized objective value.\n\nTable 4-3\n| Branch Location | Specialty | Demand |\n|-----------------|-----------|--------|\n| Donghai City | 1 | 1000 |\n| Donghai City | 2 | 2000 |\n| Donghai City | 3 | 1500 |\n| Nanjiang City | 1 | 2000 |\n| Nanjiang City | 2 | 1000 |\n| Nanjiang City | 3 | 1000 |\n\nTable 4-4\n\n| Type | Number of People | Suitable Specialty | Preferred Specialty | Preferred City |\n|------|------------------|--------------------|---------------------|----------------|\n| 1 | 1500 | 1,2 | 1 | Donghai |\n| 2 | 1500 | 2,3 | 2 | Donghai |\n| 3 | 1500 | 1,3 | 1 | Nanjiang |\n| 4 | 1500 | 1,3 | 3 | Nanjiang |\n| 5 | 1500 | 2,3 | 3 | Donghai |\n| 6 | 1500 | 3 | 3 | Nanjiang |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "2000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 27 (MIT)" - }, - { - "id": "lpmilp-029-diet-problem", - "question": "Suppose a certain animal needs at least $700 \\mathrm{~g}$ of protein, $30 \\mathrm{~g}$ of minerals, and $100 \\mathrm{mg}$ of vitamins daily. There are 5 types of feed available, and the nutritional content and price per kilogram of each type of feed are shown in Table 1-5:\nTry to formulate a linear programming model that meets the animal's growth needs while minimizing the cost of selecting the feed.\nTable 1-6\n| Feed | Protein (g) | Minerals (g) | Vitamins (mg) | Price (¥/kg) | Feed | Protein (g) | Minerals (g) | Vitamins (mg) | Price (¥/kg) |\n|------|-------------|--------------|---------------|--------------|------|-------------|--------------|---------------|--------------|\n| 1 | 3 | 1 | 0.5 | 0.2 | 4 | 6 | 2 | 2 | 0.3 |\n| 2 | 2 | 0.5 | 1 | 0.7 | 5 | 18 | 0.5 | 0.8 | 0.8 |\n| 3 | 1 | 0.2 | 0.2 | 0.4 | | | | | |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "32.43589744", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 28 (MIT)" - }, - { - "id": "lpmilp-030-factory-planning-problem", - "question": "A factory produces three types of products: I, II, and III. Each product must undergo two processing stages, A and B. The factory has two types of equipment to complete stage A (A1, A2) and three types of equipment to complete stage B (B1, B2, B3).\n\nThe production rules are as follows:\n- Product I can be processed on any type of A equipment (A1 or A2) and any type of B equipment (B1, B2, or B3).\n- Product II can be processed on any type of A equipment (A1 or A2), but for stage B, it can only be processed on B1 equipment.\n- Product III can only be processed on A2 equipment for stage A and B2 equipment for stage B.\n\nThe detailed data for processing time per piece, costs, sales price, and machine availability is provided in the table below. The objective is to determine the optimal production plan to maximize the factory's total profit.\n\nData Table\n| Equipment | Product I | Product II | Product III | Effective Machine Hours | Full - load Equipment Cost (Yuan) | Processing Cost per Machine Hour (Yuan/hour) |\n| :--- | :--- | :--- | :--- | :--- | :--- | :--- |\n| A1 | 5 | 10 | - | 6000 | 300 | 0.05 |\n| A2 | 7 | 9 | 12 | 10000 | 321 | 0.03 |\n| B1 | 6 | 8 | - | 4000 | 250 | 0.06 |\n| B2 | 4 | - | 11 | 7000 | 783 | 0.11 |\n| B3 | 7 | - | - | 4000 | 200 | 0.05 |\n| Raw Material Cost (Yuan/piece) | 0.25 | 0.35 | 0.5 | - | - | - |\n| Unit Price (Yuan/piece) | 1.25 | 2 | 2.8 | - | - | - |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "1190.38", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 29 (MIT)" - }, - { - "id": "lpmilp-031-production-planning-problem", - "question": "A product consists of three components produced by four workshops, each with a limited number of production hours. Table 1.4 below provides the production rates of the three components. The objective is to determine the number of hours each workshop should allocate to each component to maximize the number of completed products. Formulate this problem.\n\nTable 1.4\n\n| Workshop | Production Capacity (hours) | Production Rate (units/hour) | | |\n| :------: | :-------------------------: | :--------------------------: | - | - |\n| | | Component 1 | Component 2 | Component 3 |\n| A | 100 | 10 | 15 | 5 |\n| B | 150 | 15 | 10 | 5 |\n| C | 80 | 20 | 5 | 10 |\n| D | 200 | 10 | 15 | 20 |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "2924.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 30 (MIT)" - }, - { - "id": "lpmilp-032-knapsack", - "question": "A wealthy noble passed away, leaving the following inheritance:\n\n- A painting by Caillebotte: $25000\n- A bust of Diocletian: $5000\n- A Yuan dynasty Chinese vase: $20000\n- A 911 Porsche: $40000\n- Three diamonds: each $12000\n- A Louis XV sofa: $3000\n- Two very precious Jack Russell racing dogs: each $3000 (will stipulates they must not be separated)\n- A sculpture from 200 AD: $10000\n- A sailing boat: $15000\n- A Harley Davidson motorcycle: $10000\n- A piece of furniture once belonging to Cavour: $13000,\n\nwhich must be shared between two sons. How to formulate a mathematical program and solve it to minimize the difference in value between the two parts?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "1000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 31 (MIT)" - }, - { - "id": "lpmilp-033-bin-packing", - "question": "The current problem faced by the company is how to use the fewest number of containers to pack the currently needed goods for transportation, while considering the weight of the goods, specific packaging requirements, and inventory limitations. Professional modeling and analysis are needed for a batch of goods’ transportation strategy to ensure maximum utilization of the limited container space.\n\nThe company currently has a batch to be transported, with each container able to hold a maximum of 60 tons of goods and each container used must load at least 18 tons of goods. The goods to be loaded include five types: A, B, C, D, and E, with quantities of 120, 90, 300, 90, and 120 respectively. The weights are 0.5 tons for A, 1 ton for B, 0.4 tons for C, 0.6 tons for D, and 0.65 tons for E. Additionally, to meet specific usage requirements, every time A goods are loaded, at least 1 unit of C must also be loaded, but loading C alone does not require simultaneously loading A; and considering the demand limitation for D goods, each container must load at least 12 units of D.\n\nEstablish an operations research model so that the company can use the fewest number of containers to pack this batch of goods.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "7.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 32 (MIT)" - }, - { - "id": "lpmilp-034-flow-shop-scheduling", - "question": "A fabric dyeing plant has 3 dyeing vats. Each batch of fabric must be dyed in sequence in each vat: first, the second, and third vats. The plant must color five batches of fabric of different sizes. The time required in hours to dye batch $i$ in vat $j$ is given in the following matrix:\n\n$$\n\\left(\\begin{array}{ccc}\n3 & 1 & 1 \\\\\n2 & 1.5 & 1 \\\\\n3 & 1.2 & 1.3 \\\\\n2 & 2 & 2 \\\\\n2.1 & 2 & 3\n\\end{array}\\right)\n$$\n\nSchedule the dyeing operations in the vats to minimize the completion time of the last batch.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "14.1", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 33 (MIT)" - }, - { - "id": "lpmilp-035-capacitated-vehicle-routing-prob", - "question": "The Vehicle Routing Problem (VRP) was first proposed by Dantzig and Ramser in 1959. It is a classic combinatorial optimization problem. The basic VRP can be described as follows: in a certain area, there is a number of customers and a distribution center or depot. Customers are generally located at different positions, and each has a specific demand for goods. The distribution center needs to dispatch a fleet of vehicles and design appropriate delivery routes to fulfill the demands of all customers. The objective of VRP is to optimize a certain benefit metric while satisfying all customer demands. The benefit metric is usually presented as an objective function, which varies according to the company's requirements. Common objective functions include minimizing the total distance traveled by vehicles, minimizing the total delivery time, or minimizing the number of vehicles used. In addition to satisfying customer demands, VRP often needs to consider various other constraints, leading to several variants. For example, if the vehicle's load cannot exceed its maximum capacity, the problem becomes the Capacitated Vehicle Routing Problem (CVRP). If each customer's delivery must be made within a specific time frame, the problem becomes the Vehicle Routing Problem with Time Windows (VRPTW).\n\nThe Vehicle Routing Problem with Time Windows (VRPTW) is a classic variant of the VRP. There are many real-world applications of VRPTW, as customer locations often have service time windows. For instance, some logistics centers need to stock parcels during off-peak hours, and large supermarkets need to replenish goods outside of business hours. Real-time delivery services like food delivery also require strict delivery time windows. Time windows can be categorized as hard or soft. A Hard Time Window (HTW) means that a vehicle must arrive at the delivery point within or before the time window; late arrivals are not permitted. If a vehicle arrives early, it must wait until the time window opens to begin service. This is common in scenarios like supermarket restocking and logistics center inbound operations. A Soft Time Window (STW) means that a vehicle is not strictly required to arrive within the time window, but it is encouraged to do so. A penalty is incurred for early or late arrivals. This is applicable in scenarios such as meal delivery, school bus services, and industrial deliveries.\n\nThe Vehicle Routing Problem with Hard Time Windows (VRPHTW) can be described as follows: within a region, there is a set of customer locations and a central depot. Vehicles must start from the depot and return to the depot, following continuous paths. Each customer must be served by exactly one vehicle, and vehicles have a limited capacity. Each customer has a specific service time window, and service is only accepted within this window. A vehicle can arrive at a customer location early and wait for the time window to open, or it can arrive within the time window to provide service. Service can only begin within the time window, and the service duration is known. The distribution center must arrange an optimal delivery plan to both complete the delivery tasks and minimize travel costs. Because VRPHTW does not allow for delays, it, like the VRP, primarily emphasizes the minimization of travel costs along the routes.\n\n Now we consider a major enterprise logistics provider, 'Global Logistics', is responsible for providing precise material delivery services for multiple high-end office buildings and shops in a city's central business district (CBD). Due to traffic control in the CBD and the specific receiving requirements of the customers, the delivery task is highly challenging.\n\n**Specific Requirements:**\n\n1. **Delivery Task**: There are 20 customers requiring delivery service on the day, and the demands of all customers must be met.\n2. **Vehicle Constraints**: The company can use at most 5 trucks, and the capacity of each truck is 200 units.\n3. **Capacity Constraint**: The total demand of all customers on a single route must not exceed the truck's maximum capacity (200 units).\n4. **Time Window Constraint**: Each customer has a strict 'hard time window.' Service must begin within this specified time window. Early arrivals must wait, and late arrivals are not permitted.\n5. **Service Time**: Due to the complex handover procedures at customer sites, a fixed service time of 90 minutes is required for unloading, handover, and paperwork at each customer location.\n6. **Optimization Objective**: While satisfying all constraints, the company's objective is to **minimize the total distance traveled by all vehicles** to reduce operational costs.\n\n**Data Details:**\n\n* **Central Depot (Depot 0)**:\n * Coordinates: (40, 50)\n * Operating Time Window: [0, 1236] (minutes)\n* **Customer Locations (Customers 1-20)**: The coordinates, demand, service time window, and service duration for each customer are shown in the table below.\n\n| Customer ID | Coordinates (X, Y) | Demand (units) | Time Window (minutes) | Service Duration (minutes) |\n| :--- | :--- | :--- |:--- | :--- |\n| 1 | (45, 68) | 10 | [912, 967] | 90 |\n| 2 | (45, 70) | 30 | [825, 870] | 90 |\n| 3 | (42, 66) | 10 | [65, 146] | 90 |\n| 4 | (42, 68) | 10 | [727, 782] | 90 |\n| 5 | (42, 65) | 10 | [15, 67] | 90 |\n| 6 | (40, 69) | 20 | [621, 702] | 90 |\n| 7 | (40, 66) | 20 | [170, 225] | 90 |\n| 8 | (38, 68) | 20 | [255, 324] | 90 |\n| 9 | (38, 70) | 10 | [534, 605] | 90 |\n| 10 | (35, 66) | 10 | [357, 410] | 90 |\n| 11 | (35, 69) | 10 | [448, 505] | 90 |\n| 12 | (25, 85) | 20 | [652, 721] | 90 |\n| 13 | (22, 75) | 30 | [30, 92] | 90 |\n| 14 | (22, 85) | 10 | [567, 620] | 90 |\n| 15 | (20, 80) | 40 | [384, 429] | 90 |\n| 16 | (20, 85) | 40 | [475, 528] | 90 |\n| 17 | (18, 75) | 20 | [99, 148] | 90 |\n| 18 | (15, 75) | 20 | [179, 254] | 90 |\n| 19 | (15, 80) | 10 | [278, 345] | 90 |\n| 20 | (30, 50) | 10 | [10, 73] | 90 |\n\nNow, please provide an operations research model for this VRPHTW.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "175.37", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 34 (MIT)" - }, - { - "id": "lpmilp-036-production-planning-problem", - "question": "A factory produces two types of microcomputers, A and B. Each type of microcomputer requires the same two production processes. The processing time, profit from sales, and the maximum weekly processing capacity for each type are shown in Table 3.1.\n\nTable 3.1\n\n| Process | Model | | Maximum Weekly Processing Capacity |\n| :---: | :---: | :---: | :---: |\n| | $\\\\mathrm{A}$ | $\\\\mathrm{B}$ | |\n| I (hours / unit) | 4 | 6 | 150 |\n| II (hours / unit) | 3 | 2 | 70 |\n| Profit ($ per unit) | 300 | 450 | |\n\nThe expected values for the factory's operational goals are as follows:\n\n$p_{1}$: The total weekly profit must not be less than $10,000.\n\n$p_{2}$: Due to contractual requirements, at least 10 units of Model A and at least 15 units of Model B must be produced per week.\n\n$p_{3}$: The weekly production time for Process I should be exactly 150 hours, and the production time for Process II should be fully utilized, with potential overtime if necessary.\n\nTry to establish the mathematical programming model for this problem in oder to maximize total profit.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "11250.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 35 (MIT)" - }, - { - "id": "lpmilp-037-flow-shop-scheduling", - "question": "There are three different products to be processed on three machine tools. Each product must first be processed on machine 1, then sequentially on machines 2 and 3. The order of processing the three products on each machine should remain the same. Assuming $t_{ij}$ represents the time to process the $i$-th product on the $j$-th machine, how should the schedule be arranged to minimize the total processing cycle for the three products? The timetable is as follows:\n| Product | Machine 1 | Machine 2 | Machine 3 |\n|---------|-----------|-----------|-----------|\n| Product 1 | 2 | 3 | 1 |\n| Product 2 | 4 | 2 | 3 |\n| Product 3 | 3 | 5 | 2 |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "14.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 36 (MIT)" - }, - { - "id": "lpmilp-038-transportation-airline-industry", - "question": "A company plans to transport goods between the city and the suburb and needs to choose the most environmentally friendly transportation method. The company can choose from the following three methods: motorcycle, small truck, and large truck. Each motorcycle trip produces 40 units of pollution, each small truck trip produces 70 units of pollution, and each large truck trip produces 100 units of pollution. The company's goal is to minimize total pollution.\n\nThe company can only choose two out of these three transportation methods.\n\nDue to certain road restrictions, the number of motorcycle trips cannot exceed 8.\n\nEach motorcycle trip can transport 10 units of products, each small truck trip can transport 20 units of products, and each large truck trip can transport 50 units of products. The company needs to transport at least 300 units of products.\n\nThe total number of trips must be less than or equal to 20.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "600.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 37 (MIT)" - }, - { - "id": "lpmilp-039-production-planning-problem", - "question": "The independent country of Carelland mainly exports four commodities: steel, engines, electronic components, and plastic. Carelland's Minister of Finance (i.e., Minister of Economy) wants to maximize exports and minimize imports. The unit prices of steel, engines, electronics, and plastic on the world market are, in local currency (Klunz), 500, 1500, 300, 1200 respectively. Producing 1 unit of steel requires 0.02 units of engines, 0.01 units of plastic, 250 Klunz of other imported goods, and 6 person-months of labor. Producing 1 unit of engines requires 0.8 units of steel, 0.15 units of electronic components, 0.11 units of plastic, 300 Klunz of imported goods, and 1 person-year. One unit of electronics requires: 0.01 units of steel, 0.01 units of engines, 0.05 units of plastic, 50 Klunz of imported goods, and 6 person-months of labor. One unit of plastic requires: 0.03 units of engines, 0.2 units of steel, 0.05 units of electronic components, 300 Klunz of imported goods, and 2 person-years. Engine production is limited to 650000 units, and plastic production is limited to 60000 units. The total available labor force per year is 830000 person-months. Write a mathematical program to maximize domestic GDP and solve the problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "36288567.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 38 (MIT)" - }, - { - "id": "lpmilp-040-profit-maximization-problem", - "question": "A person has a fund of 500,000 yuan and the following investment projects available in the next three years:\n\n(1) Investment can be made at the beginning of each year within three years, and the annual profit is 20% of the investment amount.\n\n(2) Investment is only allowed at the beginning of the first year, and can be recovered at the end of the second year, with the total principal and interest being 150% of the investment amount. However, this type of investment is limited to no more than 120,000 yuan.\n\n(3) Investment at the beginning of the second year, recoverable at the end of the second year, with the total principal and interest being 160% of the investment amount. This type of investment is limited to 150,000 yuan.\n\n(4) Investment is allowed at the beginning of the third year, recoverable in one year, with a profit of 40%, and the investment limit is 100,000 yuan.\n\nDetermine an investment plan for the person that maximizes the total principal and interest by the end of the third year.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "964640.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 39 (MIT)" - }, - { - "id": "lpmilp-041-production-planning-problem", - "question": "Two steel furnaces at a steel plant each use two methods of steelmaking simultaneously. The first method takes $a=2$ hours per furnace and costs $m=50$ in fuel expenses; the second method takes $b=3$ hours per furnace and costs $n=70$ in fuel expenses. Assuming each furnace produces $k=10$ tons of steel regardless of the method used, and that at least $d=30$ tons of steel must be produced within $c=12$ hours, how should these two methods be allocated to minimize fuel expenses? Formulate this problem as a linear programming model.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "150.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 40 (MIT)" - }, - { - "id": "lpmilp-042-transportation-problem", - "question": "A production base needs to extract raw materials from warehouses A and B every day for production. The required raw materials are: at least 240 pieces of raw material A, at least 80 kg of raw material B, and at least 120 tons of raw material C. It is known that: Each truck from warehouse A can transport back to the production base 4 pieces of raw material A, 2 kg of raw material B, 6 tons of raw material C, with a freight cost of 200 yuan per truck; each truck from warehouse B can transport back to the production base 7 pieces of raw material A, 2 kg of raw material B, 2 tons of raw material C per day, with a freight cost of 160 yuan per truck. Question: In order to meet production needs, how many trucks should be dispatched daily from warehouse A and warehouse B to minimize the total freight cost?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "6800.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 41 (MIT)" - }, - { - "id": "lpmilp-043-capacitated-facility-location-pr", - "question": "Given that there are $m=2$ production points for a certain type of material, where the output at the $i$-th point $(i=1,2)$ is $a_i$, $a_1 = 100$, and $a_2 = 150$. This material is to be shipped to $n=2$ demand points, where the demand at the $j$-th point $(j=1, 2)$ is $b_j$, $b_1 = 80$, and $b_2 = 120$. It is known that $\\sum_i a_i \\geqslant \\sum_j b_j$. It is also known that when shipping from production points to demand points, it must pass through one of the $p=2$ intermediate marshaling stations. If the $k$-th $(k=1, 2)$ intermediate marshaling station is used, a fixed cost $f_k$ is incurred regardless of the transshipment volume, where $f_1 = 10$ and $f_2 = 15$. The $k$-th intermediate marshaling station has a maximum transshipment capacity limitation $q_k$, where $q_1 = 100$ and $q_2 = 100$. Let $c_{i k}$ and $c'_{k j}$ denote the unit transportation cost from $i$ to $k$ and from $k$ to $j$, respectively, where $c_{11}=2$, $c_{12}=3$, $c_{21}=4$, $c_{22}=1$, $c'_{11}=3$, $c'_{12}=2$, $c'_{21}=1$, and $c'_{22}=4$. Try to determine a transportation plan for this material that minimizes the total cost.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "685.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 42 (MIT)" - }, - { - "id": "lpmilp-044-production-planning-problem", - "question": "A factory produces three types of products, A, B, and C. Each unit of product A requires 1 hour for technical preparation, 10 hours of direct labor, and 3 kg of materials. Each unit of product B requires 2 hours for technical preparation, 4 hours of labor, and 2 kg of materials. Each unit of product C requires 1 hour for technical preparation, 5 hours of labor, and 1 kg of materials. The available technical preparation time is 100 hours, labor time is 700 hours, and materials are 400 kg. The company offers larger discounts for bulk purchases, as detailed in Table 1-22. Determine the company's production plan to maximize profit.\nTable 1-22\n| Product A | | Product B | | Product C | |\n|:---------------|:---------:|:---------------|:---------:|:---------------|:---------:|\n| Sales Volume (pieces) | Profit (yuan) | Sales Volume (pieces) | Profit (yuan) | Sales Volume (pieces) | Profit (yuan) |\n| 0 ~ 40 | 10 | 0 ~ 50 | 6 | 0 ~ 100 | 5 |\n| 40 ~ 100 | 9 | 50 ~ 100 | 4 | Above 100 | 4 |\n| 100 ~ 150 | 8 | Above 100 | 3 | | |\n| Above 150 | 7 | | | | |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "712.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 43 (MIT)" - }, - { - "id": "lpmilp-045-assignment-problem", - "question": "A university computer lab hires 4 undergraduates (designated 1, 2, 3, and 4) and 2 graduate students (designated 5 and 6) for duty answering questions. The maximum duty hours from Monday to Friday and the hourly wage for each person are shown in Table 5-9.\n\nTable 5-9\nStudent ID | Wage (CNY/h) | Monday | Tuesday | Wednesday | Thursday | Friday\n1 | 10.0 | 6 | 0 | 6 | 0 | 7\n2 | 10.0 | 0 | 6 | 0 | 6 | 7\n3 | 9.9 | 4 | 8 | 4 | 0 | 5\n4 | 9.8 | 5 | 5 | 6 | 0 | 4\n5 | 10.8 | 4 | 0 | 4 | 8 | 0\n6 | 11.3 | 5 | 6 | 0 | 6 | 3\n\nThe lab operates from 8:00 AM to 10:00 PM, and there must be one and only one student on duty during open hours. It is also required that each undergraduate must work at least 8 hours per week, and each graduate student must work at least 7 hours per week. Additionally, each student can work no more than 2 shifts per week, and no more than 3 students can be scheduled for duty each day.\n\nBased on these conditions, establish a mathematical model to determine the work schedule that satisfies all requirements.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "717.9", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 44 (MIT)" - }, - { - "id": "lpmilp-046-farm-planning", - "question": "A certain farm has 100 hectares of land and 15,000 yuan in funds for production development. The labor force situation on the farm is 3,500 person-days in autumn and winter, and 4,000 person-days in spring and summer. If the labor force itself is not fully utilized, they can work externally, earning 2.1 yuan/person-day in spring and summer and 1.8 yuan/person-day in autumn and winter.\n\nThe farm cultivates three types of crops: soybeans, corn, and wheat, and also raises dairy cows and chickens. Crop cultivation requires no specialized investment, but raising animals involves an investment of 400 yuan per dairy cow and 3 yuan per chicken. Raising dairy cows requires allocating 1.5 hectares of land per cow to grow feed, and involves 100 person-days in autumn and winter, and 50 person-days in spring and summer per cow. The annual net income is 400 yuan per dairy cow. Raising chickens does not use land, requires 0.6 person-days in autumn and winter, and 0.3 person-days in spring and summer per chicken. Annual net income is 2 yuan per chicken. The current chicken coop can accommodate up to 3,000 chickens, and the cow barn can accommodate up to 32 dairy cows. The labor and income requirements for the three types of crops per year are shown in Table 1-9.\n\nTable 1-9\n| Item | Soybean | Corn | Wheat |\n|----------------|---------|------|-------|\n| Person-days (Autumn/Winter) | 20 | 35 | 10 |\n| Person-days (Spring/Summer) | 50 | 75 | 40 |\n| Annual Net Income (Yuan/hectare) | 175 | 300 | 120 |\n\nDetermine the farm's operating plan to maximize annual net income. Please note that workers can only work externally for full days, fractions are not allowed. It is not possible to change the crop and animal raising plans from season to season.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "20241.8", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 45 (MIT)" - }, - { - "id": "lpmilp-047-production-planning-problem", - "question": "A factory produces two models of microcomputers, A and B. Each model requires the same two processes. The processing time, sales profit, and the factory’s maximum weekly processing capacity for each model are shown in Table 3.1.\n\nTable 3.1\n\n| Process | Model | | Maximum Weekly Processing Capacity |\n| :---: | :---: | :---: | :---: |\n| | $A$ | $B$ | |\n| I (hours/unit) | 4 | 6 | 150 |\n| II (hours/unit) | 3 | 2 | 70 |\n| Profit (yuan/unit) | 300 | 450 | |\n\nGiven the factory's business goals:\n\n$p_{1}$: The total weekly profit should not be less than 10,000 yuan;\n\n$p_{2}$: Due to contract requirements, at least 10 units of model A and at least 15 units of model B must be produced each week;\n\n$p_{3}$: The processing time for Process I should be exactly 150 hours per week, and the processing time for Process II should ideally be fully utilized, with potential for appropriate overtime;\n\n$p_{4}$: If products are produced during overtime in Process II, the profit per unit is reduced by 20 yuan for model A and 25 yuan for model B, and the maximum overtime for Process II is 30 hours per week. Formulate the mathematical model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "11250.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 46 (MIT)" - }, - { - "id": "lpmilp-048-lot-sizing-problem", - "question": "A factory must rent warehouse space to cover storage needs over the next four months. The required storage areas are:\nMonth 1: 1500 m²\nMonth 2: 1000 m²\nMonth 3: 2000 m²\nMonth 4: 1200 m²\n\nWarehouse space can be rented via contracts of fixed duration. A contract of length k months (k ? {1, 2, 3, 4}) may start at the beginning of any month t provided it ends no later than Month 4 (i.e., t + k ? 1 ? 4). A contract starting in month t covers months t through t + k ? 1. The rental fee is charged per square meter per month and depends on the contract length as follows:\n1-month contract: 22 yuan per m² per month\n2-month contract: 21 yuan per m² per month\n3-month contract: 20 yuan per m² per month\n4-month contract: 19 yuan per m² per month\n\nAdditional rules and assumptions:\n\nYou may sign any number of contracts.\n\nRented area is divisible (you may rent any nonnegative real number of m²).\n\nSupply is unlimited at the listed rates.\n\nIn each month, the total active rented area must be at least the required area for that month.\n\nYou pay for the entire area specified in each contract for every month it is active, even if some capacity is unused.\n\nYour task is to choose the start times, durations, and areas of contracts to minimize the total rental cost over the four-month horizon while satisfying the monthly area requirements.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "113000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 47 (MIT)" - }, - { - "id": "lpmilp-049-lot-sizing-problem", - "question": "A store has formulated a purchase and sales plan for a certain product from July to December. It is known that the warehouse capacity must not exceed 500 units, with 200 units in stock at the end of June. Thereafter, purchases are made at the beginning of each month. Assume the purchase and selling prices of this product for each month are shown in Table 1-21. How much should be purchased and sold each month to maximize the total revenue?\n\nTable 1-21\n| Month | 7 | 8 | 9 | 10 | 11 | 12 |\n|-------|----|----|----|----|----|----|\n| Buy | 28 | 24 | 25 | 27 | 23 | 23 |\n| Sell | 29 | 24 | 26 | 28 | 22 | 25 |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "9100.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 48 (MIT)" - }, - { - "id": "lpmilp-050-military-personnel-deployment-pr", - "question": "The number of nurses required in each time period over 24 hours at a certain hospital is as follows: 2:00-6:00 - 10 people, 6:00-10:00 - 15 people, 10:00-14:00 - 25 people, 14:00-18:00 - 20 people, 18:00-22:00 - 18 people, 22:00-2:00 - 12 people. Nurses start shifts in 6 batches at 2:00, 6:00, 10:00, 14:00, 18:00, and 22:00 and work continuously for 8 hours. Please determine: If the hospital can hire contract nurses with the same working hours as regular nurses, and if the pay for regular nurses is 10 yuan/hour and for contract nurses is 15 yuan/hour, should the hospital hire contract nurses and if so, how many?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "4240.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 49 (MIT)" - }, - { - "id": "lpmilp-051-set-multi-cover", - "question": "For a certain 24-hour bus service, the number of drivers and crew members required during different time periods each day is shown in Table 1-2:\nTable 1-2\n\\begin{tabular}{|c|c|c||c|c|c|}\n\\hline Shift & Time & Required number & Shift & Time & Required number \\\\\n\\hline 1 & $6: 00 \\sim 10: 00$ & 60 & 4 & $18 ; 00 \\sim 22 ; 00$ & 50 \\\\\n\\hline 2 & $10 ; 00 \\sim 14 ; 00$ & 70 & 5 & $22 ; 00 \\sim 2 ; 00$ & 20 \\\\\n\\hline 3 & $14 ; 00 \\sim 18 ; 00$ & 60 & 6 & $2: 00 \\sim 6 ; 00$ & 30 \\\\\n\\hline\n\\end{tabular}\n\nAssuming that drivers and crew members start their shifts at the beginning of each time period and work continuously for 8 hours, determine the minimum number of drivers and crew members needed for this bus route. Formulate the linear programming model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "150.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 50 (MIT)" - }, - { - "id": "lpmilp-052-knapsack", - "question": "The Zhang family has 6 children: Harry, Hermione, Ron, Fred, George, and Ginny. The cost of taking Harry is $1200, Hermione is $1650, Ron is $750, Fred is $800, George is $800, and Ginny is $1500. Which children should the couple take to minimize the total cost of taking the children? They can take up to four children on the upcoming trip.\n\nGinny is the youngest, so the Zhang family will definitely take her.\n\nIf the couple takes Harry, they will not take Fred because Harry does not get along with him.\n\nIf the couple takes Harry, they will not take George because Harry does not get along with him.\n\nIf they take George, they must also take Fred.\n\nIf they take George, they must also take Hermione.\n\nEven though it will cost them a lot of money, the Zhang family has decided to take at least three children.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "3050.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 51 (MIT)" - }, - { - "id": "lpmilp-053-production-planning-problem", - "question": "Given that a certain factory plans to produce three types of products, I, II, and III, each product needs to be processed on equipment $A, B, C$ as shown in Table 2-3:\n\nTable 2-3\n| Equipment Code | I | II | III | Effective Monthly Equipment Hours |\n|----------------|----|----|-----|----------------------------------|\n| A | 8 | 2 | 10 | 300 |\n| B | 10 | 5 | 8 | 400 |\n| C | 2 | 13 | 10 | 420 |\n| Unit Product Profit (per thousand yuan) | 3 | 2 | 2.9 | |\n\nHow can the equipment capacity be fully utilized to maximize production profit? The quantity of each product must be an integer.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "134.5", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 52 (MIT)" - }, - { - "id": "lpmilp-054-set-multi-cover", - "question": "A master's student in Operations Research at a certain university is required to select two courses in mathematics, two in operations research, and two in computer science from a total of seven courses: Calculus, Operations Research, Data Structures, Management Statistics, Computer Simulation, Computer Programming, and Forecasting. Some courses belong to only one category: Calculus falls under Mathematics, Computer Programming under Computer Science. However, some courses fall under multiple categories: Operations Research can be considered both Operations Research and Mathematics, Data Structures both Computer Science and Mathematics, Management Statistics both Mathematics and Operations Research, Computer Simulation both Computer Science and Operations Research, and Forecasting both Operations Research and Mathematics. Courses that fall under multiple categories can fulfill the requirement of both categories simultaneously. Additionally, some courses have prerequisites: Computer Simulation or Data Structures requires Computer Programming first, Management Statistics requires Calculus first, and Forecasting requires Management Statistics first. The question is: What is the minimum number of courses a master's student must take, and which specific courses, to meet the above requirements?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "4.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 53 (MIT)" - }, - { - "id": "lpmilp-055-lot-sizing-problem", - "question": "A trading company specializes in the wholesale business of certain grains. The company currently has a warehouse with a capacity of 5000 dan. On January 1, the company has 1000 dan of grain in stock and 20,000 yuan in funds. The estimated grain prices for the first quarter are shown in Table 1-8.\n\nTable 1-8\n| Month | Purchase Price (yuan/dan) | Selling Price (yuan/dan) |\n|-------|---------------------------|--------------------------|\n| 1 | 2.85 | 3.10 |\n| 2 | 3.05 | 3.25 |\n| 3 | 2.90 | 2.95 |\n\nThe purchased grains will be delivered in the same month but can only be sold in the next month, and payment is required upon delivery. The company hopes to have an inventory of 2000 dan at the end of the quarter. What purchasing and selling strategy should be adopted to maximize the total profit over the three months?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "-700.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 54 (MIT)" - }, - { - "id": "lpmilp-056-cutting-stock-problem", - "question": "Assuming a paper mill receives three orders for rolls of paper, with length and width requirements as shown in Table 1.2.\n\nTable 1.2\n\n| Order Number | Width (meters) | Length (meters) |\n| :---: | :---: | :---: |\n| 1 | 0.5 | 1000 |\n| 2 | 0.7 | 3000 |\n| 3 | 0.9 | 2000 |\n\nThe mill produces rolls of paper with standard widths of 1 meter and 2 meters. Assuming the length of the rolls is unlimited and can be spliced to reach the required length, how should the rolls be cut to minimize the area of waste?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "600.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 55 (MIT)" - }, - { - "id": "lpmilp-057-farm-planning", - "question": "Vicky and David have just bought a farm in the Yarra Valley, and they are considering using it to grow apples, pears, oranges, and lemons. The profit for growing one acre of apples is $2000, for one acre of pears is $1800, for one acre of oranges is $2200, and for one acre of lemons is $3000. To achieve maximum profit, how many acres of land should they use to grow each type of fruit? Vicky and David have just bought a farm in the Yarra Valley with a total area of 120 acres.\n\nThe land used to grow apples should be at least twice the land used to grow pears.\n\nThe land used to grow apples should be at least three times the land used to grow lemons.\n\nThe land used to grow oranges must be twice the land used to grow lemons if lemons are grown. If no lemons are grown, then we do not have this constraint.\n\nVicky and David are unwilling to grow more than two types of fruit.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "264000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 56 (MIT)" - }, - { - "id": "lpmilp-058-blending-problem", - "question": "A candy factory uses raw materials A, B, and C to process three different brands of candies, A, B, and C. It is known that the content of A, B, and C in each brand of candy, the cost of raw materials, the monthly limit of each raw material, and the unit processing fee and selling price of the three brands of candies are shown in Table 1-7.\n\nTable 1-7\n\n| Item | A | B | C | Raw Material Cost (Yuan/kg) | Monthly Limit (kg) |\n|:----------------|:---------------|:---------------|:---------------|:-----------------------------|:-------------------|\n| A | ? 60% | ? 15% | | 2.00 | 2000 |\n| B | | | | 1.50 | 2500 |\n| C | ? 20% | ? 60% | ? 50% | 1.00 | 1200 |\n| Processing Fee (Yuan/kg) | 0.50 | 0.40 | 0.30 | | |\n| Selling Price (Yuan/kg) | 3.40 | 2.85 | 2.25 | | |\n\nHow many kilograms of each of the three brands of candies should the factory produce each month to maximize the profit?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "6160.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 57 (MIT)" - }, - { - "id": "lpmilp-059-travelingsalesman", - "question": "A traveling salesman must visit 7 customers at 7 different locations, with the (symmetric) distance matrix as follows:\n\n| | 1 | 2 | 3 | 4 | 5 | 6 | 7 |\n| :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |\n| 1 | - | 86 | 49 | 57 | 31 | 69 | 50 |\n| 2 | | - | 68 | 79 | 93 | 24 | 5 |\n| 3 | | | - | 16 | 7 | 72 | 67 |\n| 4 | | | | - | 90 | 69 | 1 |\n| 5 | | | | | - | 86 | 59 |\n| 6 | | | | | | - | 81 |\n\nFormulate a mathematical program to determine the visiting order starting and ending at location 1 to minimize the travel distance.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "153.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 58 (MIT)" - }, - { - "id": "lpmilp-060-capacitated-facility-location-pr", - "question": "A product can be processed on any one of the four devices: A, B, C, or D. The preparation completion costs when each device is enabled, the unit production cost for the product, and the maximum processing capacity of each device are shown in Table 5-7. If 2000 units of the product need to be produced, how can the total cost be minimized? Try to establish a mathematical model.\n\nTable 5-7\n| Device | Prep Completion Cost (Yuan) | Unit Production Cost (Yuan/Unit) | Maximum Processing Capacity (Units) |\n|--------|------------------------------|----------------------------------|------------------------------------|\n| A | 1000 | 20 | 900 |\n| B | 920 | 24 | 1000 |\n| C | 800 | 16 | 1200 |\n| D | 700 | 28 | 1600 |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "37000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 59 (MIT)" - }, - { - "id": "lpmilp-061-knapsack", - "question": "The Zhang family is deciding to invest in several different restaurants. The annual revenue of Restaurant A is $15,000, Restaurant B is $40,000, Restaurant C is $30,000, and Restaurant D is $50,000. They need to decide whether to purchase each restaurant, with each restaurant being able to be purchased only once. Help them decide which restaurants to buy to maximize their annual income.\nThe cost of Restaurant A is 1.6 million, Restaurant B is 2.5 million, Restaurant C is 1.8 million, and Restaurant D is 3 million. The Zhang family's investment budget is 6 million.\n\nIf they purchase Restaurant D, then they cannot purchase Restaurant A.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "90000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 60 (MIT)" - }, - { - "id": "lpmilp-062-transportation-problem", - "question": "A farmer needs to transport 1000 units of fresh produce from the farm to a nearby market. The farmer has three transportation options: a horse, a bicycle, and a handcart. Since both the bicycle and handcart are very physically demanding, the farmer wants to choose only one of these two transportation methods. The horse generates 80 units of pollution per trip, the bicycle generates 0 units of pollution, and the handcart generates 0 units of pollution. The total amount of pollution generated by all trips must not exceed 1000 units. At least 8 trips must be made using the horse. The horse, bicycle, and handcart can carry 55 units, 30 units, and 40 units of produce per trip respectively. The farmer needs to ensure that the total amount of transported produce is at least 1000 units while minimizing the total amount of pollution. What is the minimum amount of pollution that the farmer can achieve?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "640.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 61 (MIT)" - }, - { - "id": "lpmilp-063-knapsack", - "question": "A company needs to decide whether to hire some of the five candidates to join their R&D team. The salary requirements for candidates F, G, H, I, and J are $12,000, $15,000, $18,000, $5,000, and $10,000 respectively. The company wants to minimize the total amount paid to candidates without exceeding the budget.\n\nThe company's budget is $40,000 and they wish to hire a maximum of 4 new employees.\n\nThe skill levels of the candidates are as follows:\nCandidate F: Level 2\nCandidate G: Level 3\nCandidate H: Level 4\nCandidate I: Level 1\nCandidate J: Level 2\n\nThe company needs to ensure that the total skill level of the hired employees is at least 8.\n\nThe project management experience years of each candidate are as follows:\nCandidate F: 1 year\nCandidate G: 2 years\nCandidate H: 2 years\nCandidate I: 5 years\nCandidate J: 4 years\n\nThey hope the total project management experience of the team is at least 8 years.\n\nDue to the similar technical background of candidates G and J, the company can choose at most one of them.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "38000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 62 (MIT)" - }, - { - "id": "lpmilp-064-production-planning-problem", - "question": "A company produces two types of products: microwave ovens and water heaters, which are manufactured in both workshops A and B. It is known that apart from the purchased parts, the production of one microwave oven requires 2 hours of processing in workshop A and 1 hour of assembly in workshop B. The production of one water heater requires 1 hour of processing in workshop A and 3 hours of assembly in workshop B. After production, both products need inspection, sales, and other procedures. The inspection and sales cost for each microwave oven is 30 yuan, and for each water heater is 50 yuan. Workshop A has 250 hours of available production time per month, with each hour costing 80 yuan; workshop B has 150 hours of available production time per month, with each hour costing 20 yuan. It is estimated that an average of 80 microwave ovens and 50 water heaters can be sold per month next year. Based on these actual conditions, the company has established the following monthly plan constraints:\n\n1. Inspection and sales costs should not exceed 5500 yuan per month;\n2. At least 80 microwave ovens should be sold per month;\n3. The production hours of both workshops A and B should be fully utilized, and overtime for workshop A and B are allowed.\n4. Overtime in workshop A should not exceed 20 hours; we do not have upper limit on workshop B's overtime.\n5. At least 50 water heaters should be sold per month.\n\nTry to determine the monthly production plan for the company.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "30500.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 63 (MIT)" - }, - { - "id": "lpmilp-065-production-planning-problem", - "question": "A toy company manufactures three types of tabletop golf toys, each requiring different manufacturing techniques. The high-end type requires 17 hours of manufacturing labor, 8 hours of inspection, and yields a profit of 300 yuan per unit. The mid-range type requires 10 hours of labor, 4 hours of inspection, and yields a profit of 200 yuan per unit. The low-end type requires 2 hours of labor, 2 hours of inspection, and yields a profit of 100 yuan per unit. Available labor hours are 1000, and available inspection hours are 500. Additionally, market forecasts indicate a demand of no more than 50 units for the high-end type, no more than 80 units for the mid-range type, and no more than 150 units for the low-end type. Determine the production plan for the company to maximize profit.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "25000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 64 (MIT)" - }, - { - "id": "lpmilp-066-lot-sizing-problem", - "question": "The market demand for products I and II is as follows: Product I requires 10,000 units per month from January to April, 30,000 units per month from May to September, and 100,000 units per month from October to December. Product II requires 15,000 units per month from March to September and 50,000 units per month during other months. The cost of producing these two products at a certain factory is as follows: Product I costs 5 yuan per unit to produce from January to May, and 4.50 yuan per unit from June to December; Product II costs 8 yuan per unit to produce from January to May, and 7 yuan per unit from June to December. The factory's combined production capacity for both products should not exceed 120,000 units per month. Product I has a volume of 0.2 cubic meters per unit, Product II has a volume of 0.4 cubic meters per unit, and the factory's warehouse capacity is 15,000 cubic meters. If the factory's warehouse space is insufficient, external warehouse space can be rented. Using the factory’s own warehouse costs 1 yuan per cubic meter per month, while renting an external warehouse increases this cost to 1.5 yuan per cubic meter per month. Given that the initial inventory of both products at the beginning of July is zero, how should production be scheduled from July to December to minimize the total production and inventory costs while meeting market demand?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "3160500.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 65 (MIT)" - }, - { - "id": "lpmilp-067-transportation-problem", - "question": "There are two coal yards A and B, each receiving no less than 80 tons and 100 tons of coal per month, respectively. They are responsible for supplying coal to three residential areas, which need 55 tons, 75 tons, and 50 tons of coal per month, respectively. Coal yard A is located 10 kilometers, 5 kilometers, and 6 kilometers from these three residential areas. Coal yard B is located 4 kilometers, 8 kilometers, and 15 kilometers from these three residential areas. How should these two coal yards distribute coal to the three residential areas to minimize the ton-kilometers of transportation?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "1030.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 66 (MIT)" - }, - { - "id": "lpmilp-068-cutting-stock-problem", - "question": "A steel reinforcement workshop produces a batch of steel bars (with the same diameter), consisting of 90 pieces of 3 meters in length and 60 pieces of 4 meters in length. It is known that each piece of raw steel bar used is 10 meters in length. How can the raw material be cut most efficiently? Establish a linear programming model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "53.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 67 (MIT)" - }, - { - "id": "lpmilp-069-travelingsalesman", - "question": "The famous Traveling Salesman Problem (TSP) in operations research can be described as follows: A traveling salesman departs from a certain city, and must visit each city exactly once before returning to the original starting city. The distances between the cities are provided in the table below (the entry at row i and column j represents the cost of going from city i to city j)\n| City | 1 | 2 | 3 | 4 |\n| ---- | ------ | ------ | ------ | ------ |\n| 1 | 0 | 10 | 20 | 12 |\n| 2 | 10 | 0 | 5 | 10 |\n| 3 | 20 | 5 | 0 | 8 |\n| 4 | 15 | 12 | 8 | 0 |\n\nWhat route should the salesman choose to travel in order to minimize the total distance? Try to formulate an integer programming model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "35.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 68 (MIT)" - }, - { - "id": "lpmilp-070-assignment-problem", - "question": "Consider assigning $n=2$ factories to $n$ locations. The transportation volume between factory $i$ and factory $j$ is $d_{ij}$, and the unit transportation cost from location $p$ to location $q$ is $c_{pq}$. The specific values are shown in the following table: Table 1.1\n\n| | Transportation volume to Location 1 | Transportation volume to Location 2 | Transportation cost to Location 1 | Transportation cost to Location 2 |\n| :----: | :---------------------------------: | :---------------------------------: | :-------------------------------: | :-------------------------------: |\n| Factory 1 | 10 | 20 | 5 | 8 |\n| Factory 2 | 30 | 40 | 6 | 7 |\n\nIn order to minimize the total transportation cost, formulate this problem as an integer model.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "330.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 69 (MIT)" - }, - { - "id": "lpmilp-071-knapsack", - "question": "The Li family plans to invest their retirement fund in commercial real estate. The annual income from Property 1 is $12,500, Property 2 is $35,000, Property 3 is $23,000, and Property 4 is $100,000. The decision to be made is whether to buy each property or not, rather than how many to buy, as there is only one of each property available. Help them decide which properties to purchase to maximize their annual income.\n\nThe cost of Property 1 is $1.5 million, Property 2 is $2.1 million, Property 3 is $2.3 million, and Property 4 is $4.2 million. The Li family's budget is $7 million.\n\nIf they purchase Property 4, they cannot purchase Property 3.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "135000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 70 (MIT)" - }, - { - "id": "lpmilp-072-knapsack", - "question": "The Li family has 5 children: Alice, Bob, Charlie, Diana, and Ella. The cost to take Alice is $1000, Bob is $900, Charlie is $600, Diana is $500, and Ella is $700. Which children should the couple take to minimize the total cost of taking the children?\n\nThey can take up to 3 children on the upcoming trip.\n\nBob is the youngest, so the Li family will definitely take him.\n\nIf the couple takes Alice, they will not take Diana because Alice does not get along with her.\n\nIf the couple takes Bob, they will not take Charlie because Bob does not get along with him.\n\nIf they take Charlie, they must also take Diana.\n\nIf they take Diana, they must also take Ella.\n\nDespite the cost, the Li family has decided to take at least two children.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "1600.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 71 (MIT)" - }, - { - "id": "lpmilp-073-operations-optimization", - "question": "A project includes the following 7 activities, with their durations (in days) as follows: $A(4), B(3), C(5), D(2), E(10), F(10), G(1)$. The precedence relationships are also given as: $A \\rightarrow G, D ; E, G \\rightarrow F; D, F \\rightarrow C ; F \\rightarrow B$. The cost of work per day is 1000 Euros; additionally, a special machine must be rented from the start of activity $A$ to the end of activity $B$, costing 5000 Euros per day. Formulate this as a linear programming problem to minimize cost and complete all activities.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "115000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 72 (MIT)" - }, - { - "id": "lpmilp-074-production-planning-problem", - "question": "There are $\\mathrm{A}$ and $\\mathrm{B}$ two products, both requiring two successive chemical reaction processes. Each unit of product $\\mathrm{A}$ needs 2 hours for the first process and 3 hours for the second process. Each unit of product $\\mathrm{B}$ needs 3 hours for the first process and 4 hours for the second process. Available time for the first process is 16 hours, and available time for the second process is 24 hours.\n\nFor each unit of product $\\mathrm{B}$ produced, 2 units of by-product $\\mathrm{C}$ are generated simultaneously, requiring no additional cost. By-product $\\mathrm{C}$ can be sold up to 5 units, and the rest must be disposed of at a cost of 2 yuan per unit.\n\nEach unit of product $\\mathrm{A}$ sold yields a profit of 4 yuan, each unit of product $\\mathrm{B}$ yields a profit of 10 yuan, and each unit of by-product $\\mathrm{C}$ sold yields a profit of 3 yuan.\n\nIn order to maximize total profit, establish the linear programming model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "57.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 73 (MIT)" - }, - { - "id": "lpmilp-075-lot-sizing-problem", - "question": "A timber storage and transport company has a large warehouse for storing and transporting timber for sale. Due to seasonal price fluctuations, the company purchases timber at the beginning of each quarter, with part of it being sold within the quarter and part being stored for future sales. It is known that the maximum storage capacity of the company's warehouse is 200,000 m³, and the storage cost is $(a+b u)$ yuan/m³, where $a=70$, $b=100$, and $u$ is the storage time (in quarters). The purchase and sale prices for each quarter and the estimated maximum sales volumes are shown in Table 1-18.\n\nTable 1-18\n| Quarter | Purchase Price (10,000 yuan/10,000 m²) | Sale Price (10,000 yuan/10,000 m²) | Estimated Maximum Sales Volume (10,000 m³) |\n|---------|----------------------------------------|------------------------------------|---------------------------------------------|\n| Winter | 410 | 425 | 100 |\n| Spring | 430 | 440 | 140 |\n| Summer | 460 | 465 | 200 |\n| Autumn | 450 | 455 | 160 |\n\nSince timber is not suitable for long-term storage, all inventory should be sold by the end of autumn. Try to establish a linear programming model for this problem to maximize the company's annual profit. Return your answer in the unit of 10000 yuan.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "4700.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 74 (MIT)" - }, - { - "id": "lpmilp-076-capacitated-facility-location-pr", - "question": "There are 10 different parts, and they can all be processed on machine \\( A \\), machine \\( B \\), or machine \\( C \\). The unit processing costs are shown in Table 5-6. Additionally, as long as any part is processed on the aforementioned machines, a one-time setup cost will be incurred regardless of whether one or multiple types of parts are processed, with the respective costs being \\( d_A = 100 \\), \\( d_B = 135 \\), and \\( d_C = 200 \\) yuan. If the requirements are:\n\n1. One piece of each of the aforementioned 10 types of parts needs to be processed;\n2. If the 1st part is processed on machine \\( A \\), then the 2nd part must be processed on machine \\( B \\) or \\( C \\); conversely, if the 1st part is processed on machine \\( B \\) or \\( C \\), then the 2nd part must be processed on machine \\( A \\);\n3. Parts 3, 4, and 5 must be processed on machines A, B, and C respectively;\n4. The number of parts processed on machine \\( C \\) should not exceed 3 types.\n\nTry to establish an integer programming mathematical model for this problem with the objective of minimizing the total cost.\n\nTable 5-6\n| Machine/Part | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |\n|--------------|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|\n| A | $10$ | $20$ | $30$ | $40$ | $50$ | $60$ | $70$ | $80$ | $90$ | $100$ |\n| B | $15$ | $25$ | $35$ | $45$ | $55$ | $65$ | $75$ | $85$ | $95$ | $105$ |\n| C | $20$ | $30$ | $40$ | $50$ | $60$ | $70$ | $80$ | $90$ | $100$ | $110$ |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "1005.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 75 (MIT)" - }, - { - "id": "lpmilp-077-operations-optimization", - "question": "A shoe store employs 5 full-time sales clerks and 4 part-time sales clerks. Their working hours and wage conditions are shown in Table 3.3.\n\nTable 3.3\n\n| | Monthly Working Hours | Sales Volume (Pairs/Hour) | Wage (Yuan/Hour) | Overtime Pay (Yuan/Hour) |\n| :---: | :---: | :---: | :---: | :---: |\n| Full-time | 160 | 5 | 1 | 1.5 |\n| Part-time | 80 | 2 | 0.6 | 0.7 |\n\nEach pair of shoes sold earns a profit of 0.3 yuan. The store has set the following goals:\n\n$p_{1}$: Achieve monthly sales of 5500 pairs;\n\n$p_{2}$: Ensure full employment of all sales clerks;\n\n$p_{3}$: Minimize overtime hours.\n\nTry to establish a model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "172.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 76 (MIT)" - }, - { - "id": "lpmilp-078-production-planning-problem", - "question": "A furniture factory needs to decide how many tables, chairs, and bookshelves to produce in order to maximize its profit. The factory can sell each table for $200, each chair for $50, and each bookshelf for $150. The manufacturing costs for each table, chair, and bookshelf are $120, $20, and $90 respectively. The profit is the difference between the selling price and the manufacturing cost. Each table, chair, and bookshelf occupy 5, 2, and 3 square meters of warehouse space respectively. Due to limited warehouse space, the total space cannot exceed 500 square meters. In addition, due to market demand, the factory needs to produce at least 10 tables and 20 bookshelves. Finally, the total number of items produced by the factory cannot exceed 200.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "9800.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 77 (MIT)" - }, - { - "id": "lpmilp-079-operations-optimization", - "question": "A company requires skilled workers and laborers for three tasks. The first task can be completed by one skilled worker alone, or by a group of one skilled worker and two laborers. The second task can be done by one skilled worker or one laborer alone. The third task can be completed by a group of five laborers, or by one skilled worker leading three laborers. The weekly wages for skilled workers and laborers are 100 yuan and 80 yuan respectively. They work 48 hours per week, but their actual effective working hours are 42 hours and 36 hours respectively. To complete these tasks, the company needs a total effective working time of 8400 hours for the first task, 10800 hours for the second task, and 18000 hours for the third task per week. The number of workers that can be recruited is limited to a maximum of 400 skilled workers and 800 laborers. Establish a mathematical model to determine how many skilled workers and laborers should be hired in order to minimize the total wage expenditure.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "84000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 78 (MIT)" - }, - { - "id": "lpmilp-080-assignment-problem", - "question": "On Danzig Street, vehicles can park on both sides of the street. Mr. Edmonds, who lives at No. 1, is organizing a party with about 30 participants, and they will arrive in 15 cars. The length of the i-th car is ?_i, in meters, as follows:\n\n| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |\n|----|----|-----|----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|\n| ?_i | 4 | 4.5 | 5 | 4.1 | 2.4 | 5.2 | 3.7 | 3.5 | 3.2 | 4.5 | 2.3 | 3.3 | 3.8 | 4.6 | 3 |\n\nIn order to avoid disturbing the neighbors, Mr. Edmonds wants to arrange parking on both sides of the street so that the total length of the street occupied by his friends' vehicles is minimized. Please provide a mathematical programming formulation and solve this problem.\nHow does the program change if the cars on one side of the street cannot occupy more than 30 meters?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "28.6", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 79 (MIT)" - }, - { - "id": "lpmilp-081-knapsack", - "question": "Changjiang Comprehensive Shopping Mall has 5000 m² of space for lease and plans to attract the following 5 types of stores as tenants. The table below shows the area occupied by each type of store for one shop, the minimum and maximum number of shops for each type within the mall, and the expected annual profit (in ten thousand yuan) per store for different numbers of stores. Each store pays 20% of its annual profit as rent to the mall. Question: How many of each type of store should the mall lease to maximize total rental income?\n\nTable 5-12\n\n| Code | Store Type | Area per Shop / m² | Min | Max | 1 Store | 2 Stores | 3 Stores |\n|------|------------|--------------------|-----|-----|---------|----------|----------|\n| 1 | Jewelry | 250 | 1 | 3 | 9 | 8 | 7 |\n| 2 | Shoes & Hats | 350 | 1 | 2 | 10 | 9 | - |\n| 3 | General Merchandise | 800 | 1 | 3 | 27 | 21 | 20 |\n| 4 | Bookstore | 400 | 0 | 2 | 16 | 10 | - |\n| 5 | Catering | 500 | 1 | 3 | 17 | 15 | 12 |", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "28.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 80 (MIT)" - }, - { - "id": "lpmilp-082-set-multi-cover", - "question": "A certain restaurant operates around the clock, and the number of waiters needed in 24 hours is shown in Table 1.1.\n\nTable 1.1\n\n| Time | Minimum Number of Waiters Needed | Time | Minimum Number of Waiters Needed |\n|:-----------:|:-------------------------------:|:-----------:|:-------------------------------:|\n| $2 \\sim 6$ | 4 | $14 \\sim 18$| 7 |\n| $6 \\sim 10$ | 8 | $18 \\sim 22$| 12 |\n| $10 \\sim 14$| 10 | $22 \\sim 2$ | 4 |\n\nEach waiter works continuously for 8 hours a day. The goal is to find the minimum number of waiters that meet the above conditions and represent this problem as a linear programming model.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "26.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 81 (MIT)" - }, - { - "id": "lpmilp-083-knapsack", - "question": "A company hopes to recruit new employees for its team. The salary requirements for candidates A, B, C, D, and E are $8100, $20000, $21000, $3000, and $8000 respectively. They need to decide whether to hire each candidate. The team wants to minimize the total amount paid to the candidates.\n\nThey hope to hire a maximum of 3 new employees.\n\nThe team has a limited budget of $35,000. They need to ensure that the total payment to the selected candidates does not exceed the budget.\n\nThe qualifications of the five candidates are as follows:\nCandidate A: Bachelor's degree;\nCandidate B: Master's degree;\nCandidate C: Doctoral degree;\nCandidate D: No degree;\nCandidate E: No degree.\nThey will select at least one candidate with a Master's or Doctoral degree.\n\nThe work experience of the five candidates is as follows:\nCandidate A: 3 years of work experience;\nCandidate B: 10 years of work experience;\nCandidate C: 4 years of work experience;\nCandidate D: 3 years of work experience;\nCandidate E: 7 years of work experience.\nThey hope the total work experience of the selected candidates is no less than 12 years.\n\nDue to the equivalent professional skills of candidates A and E, the company will choose at most one from the two.\n\nThey will hire at least 2 new employees.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "23000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 82 (MIT)" - }, - { - "id": "lpmilp-084-production-planning-problem", - "question": "A company is producing two products (X and Y). The resources required for the production of X and Y are divided into two parts: machine time for automated processing and craftsman time for manual finishing. The table below shows the number of minutes required for each product:\n\n| Item | Machine Time (minutes) | Craftsman Time (minutes) |\n| :---: | :---: | :---: |\n| X | 13 | 20 |\n| Y | 19 | 29 |\n\nThe company has 40 hours of machine time available in the next working week, but only 35 hours of craftsman time. The cost of machine time is £10 per hour, and the cost of craftsman time is £2 per hour. Idle time for machines and craftsmen incurs no cost. For each product produced (all products produced will be sold), the revenue for product X is £20, and the revenue for product Y is £30. Products can only be produced in whole units. The company has a specific contract that requires 10 units of product X to be produced for a customer each week. Formulate a model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "1861.466667", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 83 (MIT)" - }, - { - "id": "lpmilp-085-profit-maximization-problem", - "question": "Healthy Pet Foods Company produces two types of dog food: Meaties and Yummies. Each pack of Meaties contains 2 pounds of grains and 3 pounds of meat; each pack of Yummies contains 3 pounds of grains and 1.5 pounds of meat. The company believes it can sell any quantity of dog food that it can produce. Meaties sell for $2.80 per pack, and Yummies sell for $2.00 per pack. The company's production is subject to several constraints. First, a maximum of 400,000 pounds of grains can be purchased each month at a price of $0.20 per pound of grains. A maximum of 300,000 pounds of meat can be purchased each month at a price of $0.50 per pound of meat. Additionally, a special machine is required to produce Meaties, with a monthly capacity of 90,000 packs. The variable costs for mixing and packaging dog food are $0.25 per pack (Meaties) and $0.20 per pack (Yummies). Detailed information is provided in Table B-1.\n\n**Table B-1 Healthy Pet Foods Data**\n\n| | Meaties | Yummies |\n|--------------------|--------------|------------|\n| Price per pack | $2.80 | $2.00 |\n| Raw materials | | |\n| - Grains | 2.0 lbs | 3.0 lbs |\n| - Meat | 3.0 lbs | 1.5 lbs |\n| Variable cost | $0.25/pack | $0.20/pack |\n| Resources | | |\n| Meaties capacity | 90,000 packs/month | |\n| Monthly available grains | 400,000 lbs | |\n| Monthly available meat | 300,000 lbs | |\n\nAssume you are the manager of the dog food department at Healthy Pet Foods Company. Your salary is based on the department's profit, so you will try to maximize profit. How should you operate the department to maximize both the profit and your salary?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "77500.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 84 (MIT)" - }, - { - "id": "lpmilp-086-multi-commodity-transportation-p", - "question": "A transportation company has two types of trucks, Type A and Type B. Type A trucks have 20 cubic meters of refrigerated capacity and 40 cubic meters of non-refrigerated capacity. In contrast, Type B trucks have the same total capacity, but the capacities for refrigerated and non-refrigerated cargo are equal. A grocer needs to rent trucks to transport 3000 cubic meters of refrigerated cargo and 4000 cubic meters of non-refrigerated cargo. The rental cost per kilometer for Type A trucks is £30, while the rental cost per kilometer for Type B trucks is £40. How many of each type of truck should the grocer rent to minimize the total cost?\n\nTry to formulate a model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "4170.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 85 (MIT)" - }, - { - "id": "lpmilp-087-production-planning-problem", - "question": "A company uses two machines (Machine 1 and Machine 2) to produce two types of products (liquid fertilizer and solid fertilizer). To produce one unit of liquid fertilizer, it takes 50 minutes on Machine 1 and 30 minutes on Machine 2. To produce one unit of solid fertilizer, it takes 24 minutes on Machine 1 and 33 minutes on Machine 2. Fertilizers must be produced in whole units, and fractional amounts are not allowed. At the beginning of the week, there are 30 units of liquid fertilizer and 90 units of solid fertilizer in inventory. The available processing time for Machine 1 this week is expected to be 40 hours, and for Machine 2 it is expected to be 35 hours. The demand for liquid fertilizer this week is estimated at 75 units, and for solid fertilizer at 95 units. The company's policy is to maximize the total number of units of liquid fertilizer and solid fertilizer in inventory at the end of the week.\n\nFormulate a model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "1.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 86 (MIT)" - }, - { - "id": "lpmilp-088-production-planning-problem", - "question": "A company produces product A and product B. Each unit of product A sold generates a profit of £30, while each unit of product B sold generates a profit of £10. The company can allocate a maximum of 40 hours per week for production. Producing one unit of product A requires 6 hours, while producing one unit of product B requires 3 hours, and products can only be produced in whole units. Market demand requires that the quantity of product B produced must be at least three times the quantity of product A. The storage space occupied by product A is four times that of product B. The storage space's capacity is such that it can store 4 units of product A when only product A is stored.\n\nFormulate a model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "140.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 87 (MIT)" - }, - { - "id": "lpmilp-089-revenue-management-problem", - "question": "A store wants to clear out 200 shirts and 100 pairs of pants from last season. They decide to introduce two promotional packages, A and B. Package A includes one shirt and two pairs of pants, priced at £30. Package B includes three shirts and one pair of pants, priced at £50. The store does not want to sell fewer than 20 A packages and 10 B packages. How many of each package do they need to sell to maximize the revenue from the promotion?\n\nTry to establish a model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "3600.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 88 (MIT)" - }, - { - "id": "lpmilp-090-profit-maximization-problem", - "question": "A company produces two products (A and B), with a profit of £3 and £5 per unit sold, respectively. Each product must be assembled on a specific machine, requiring 12 minutes of assembly time per unit for product A and 25 minutes per unit for product B. The company's estimated effective machine working time per week is only 30 hours (due to maintenance or malfunctions). Technical constraints mean that for every five units of product A produced, at least two units of product B must be produced.\n\nTry to formulate a model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "408.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 89 (MIT)" - }, - { - "id": "lpmilp-091-transportation-airline-industry", - "question": "A school is preparing a trip for 400 students. The transportation company has 10 buses with 50 seats each and 8 minibuses with 40 seats each, but only 9 drivers are available. The rental cost for a bus is £800, and the rental cost for a minibus is £600. Calculate how many of each type of bus should be used to achieve the lowest cost.\n\nTry to formulate a model for this problem.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "6200.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 90 (MIT)" - }, - { - "id": "lpmilp-092-production-planning-problem", - "question": "A dairy processing plant uses milk to produce two dairy products, \\( A_{1} \\) and \\( A_{2} \\). One barrel of milk can be processed into 3 kg of \\( A_{1} \\) in 12 hours on Type A equipment or into 4 kg of \\( A_{2} \\) in 8 hours on Type B equipment. According to market demand, all produced \\( A_{1} \\) and \\( A_{2} \\) can be sold. The profit is 24 yuan per kilogram of \\( A_{1} \\) and 16 yuan per kilogram of \\( A_{2} \\). The processing plant can get a daily supply of 50 barrels of milk, with a total of 480 hours of labor time available from regular workers each day. The Type A equipment can process up to 100 kg of \\( A_{1} \\) per day, while the processing capacity of Type B equipment is not limited. Formulate a production plan for the plant to maximize daily profit.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "3360.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 91 (MIT)" - }, - { - "id": "lpmilp-093-blending-problem", - "question": "A company blends two types of crude oil (A and B) to produce two types of gasoline (Type I and Type II). The minimum proportion of crude oil A in gasoline Types I and II is 50% and 60%, respectively. The selling prices are 4800 yuan/t and 5600 yuan/t, respectively. The company has current inventories of 500 t of crude oil A and 1000 t of crude oil B, and they can purchase up to 1500 t of crude oil A from the market. The market price for crude oil A is: 10,000 yuan/t for purchases up to 500 t; 8,000 yuan/t for the portion exceeding 500 t but not exceeding 1000 t; 6,000 yuan/t for the portion exceeding 1000 t. How should the company plan its purchasing and processing of crude oil? Return the maximized profit in yuan.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "5000000.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 92 (MIT)" - }, - { - "id": "lpmilp-094-capacitated-lot-sizing-problem-c", - "question": "A beverage factory produces a kind of beverage to meet market demand. According to market forecasts, the sales department of the factory has determined the demand for the beverage for the next 4 weeks. The planning department, based on the actual situation of the factory, has provided the production capacity and production cost for the next 4 weeks, as shown in Table 1. When there is a surplus of beverages after meeting the demand each week, a storage cost of 0.2 thousand yuan per week per thousand boxes of beverages needs to be paid. How should the production plan be arranged to minimize the total cost (the sum of production cost and storage cost) over the four weeks while meeting the weekly market demand?\n\nTable 1 Beverage Production and Demand Data:\n\n\\begin{tabular}{c|c|c|c}\n\\hline \nWeek & Demand/1000 boxes & Production Capacity/1000 boxes & Cost per 1000 boxes/1000 yuan \\\\\n\\hline \n1 & 15 & 30 & 5.0 \\\\\n\\hline \n2 & 25 & 40 & 5.1 \\\\\n\\hline \n3 & 35 & 45 & 5.4 \\\\\n\\hline \n4 & 25 & 20 & 5.5 \\\\\n\\hline \nTotal & 100 & 135 & \\\\\n\\hline\n\\end{tabular}", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "528.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 93 (MIT)" - }, - { - "id": "lpmilp-095-cutting-stock-problem", - "question": "A steel pipe retailer sources raw steel pipes from a steel pipe factory, cuts the pipes according to customer requirements, and sells them. The raw steel pipes obtained from the factory are all 1850 mm in length. A customer now needs 15 pieces of 290 mm, 28 pieces of 315 mm, 21 pieces of 350 mm, and 30 pieces of 455 mm steel pipes. To simplify the production process, it is required that no more than 4 types of cutting patterns are used. The most frequently used cutting pattern incurs an additional cost of 1/10 of the value of a raw steel pipe, the second most frequent incurs an additional cost of 2/10, and so on. Moreover, the number of cuts for each pattern cannot be too many (a single raw steel pipe can produce up to 5 products). Additionally, to minimize waste, the leftover material for each cutting pattern should not exceed 100 mm. How should the material be cut to minimize total cost, and what is the total cost in this case?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "21.5", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 94 (MIT)" - }, - { - "id": "lpmilp-096-blending-problem", - "question": "A company mixes four types of liquid raw materials with different sulfur contents (denoted as A, B, C, and D, respectively) to produce two products (denoted as \\( \\mathrm{A} \\) and \\( \\mathrm{B} \\)). According to the production process requirements, raw materials A, B, and D must first be mixed in a mixing tank, and then the mixed liquid is further mixed with raw material C to produce \\( \\mathrm{A} \\) and \\( \\mathrm{B} \\). The sulfur contents of raw materials A, B, C, and D are \\( 3\\%, 1\\%, 2\\%, 1\\% \\) respectively, and their purchase prices are 6, 16, 10, 15 (thousand yuan per ton) respectively. The sulfur content of products \\( \\mathrm{A} \\) and \\( \\mathrm{B} \\) must not exceed \\( 2.5\\% \\) and \\( 1.5\\% \\) respectively, and their selling prices are 9, 15 (thousand yuan per ton) respectively. According to market information, there is no limit to the supply of raw materials A, B, and C, but the supply of raw material D is limited to a maximum of 50 tons. The market demand for products \\( \\mathrm{A} \\) and \\( \\mathrm{B} \\) is 100 tons and 200 tons respectively. How should the production be arranged to maximize the total profit?", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "450.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 95 (MIT)" - }, - { - "id": "lpmilp-097-production-planning-problem", - "question": "A company uses steel and aluminum as raw materials to produce two products (A and B). A single unit of product A requires 6 kg of steel, 8 kg of aluminum, 11 hours of labor, and yields a profit of 5000 yuan (excluding worker overtime pay). A single unit of product B requires 12 kg of steel, 20 kg of aluminum, 24 hours of labor, and yields a profit of 11000 yuan (excluding worker overtime pay). Products can only be produced in whole units. The company currently has 200 kg of steel, 300 kg of aluminum, and 300 hours of labor available. If workers need to work overtime, the overtime pay is 100 yuan per hour. Please develop a production plan to maximize the company's overall profit taking into account worker overtime.", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "165900.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 96 (MIT)" - }, - { - "id": "lpmilp-098-knapsack", - "question": "An electronic system is composed of 3 types of components. The system operates normally if all three components function properly. By installing one or more spare parts for any of the components, the reliability of the components can be improved. The system's operational reliability is the product of the reliabilities of each component, and the reliability of each component is a function of the number of spare parts installed. The first half of the table below shows the function relationship between the number of spare parts and the reliability of a specific component. The prices and weights of the 3 types of components are shown in rows 8 to 9 of the table. Given that the total budget for all spare parts is limited to 150 yuan, and the weight limit is 20 kg, how should spare parts be installed to maximize the system's operational reliability? \n\n\\begin{table}[h]\n\\centering\n\\begin{tabular}{|c|c|c|c|}\n\\hline\n\\textbf{Component Number} & \\textbf{1} & \\textbf{2} & \\textbf{3} \\\\ \\hline\n\\textbf{Number of Spares} & & & \\\\ \\hline\n0 & 0.5 & 0.6 & 0.7 \\\\ \\hline\n1 & 0.6 & 0.75 & 0.9 \\\\ \\hline\n2 & 0.7 & 0.95 & 1.0 \\\\ \\hline\n3 & 0.8 & 1.0 & 1.0 \\\\ \\hline\n4 & 0.9 & 1.0 & 1.0 \\\\ \\hline\n5 & 1.0 & 1.0 & 1.0 \\\\ \\hline\n\\textbf{Unit Price (yuan)} & 20 & 30 & 40 \\\\ \\hline\n\\textbf{Unit Weight (kg)} & 2 & 4 & 6 \\\\ \\hline\n\\end{tabular}\n\\caption{Spare Component Data Table}\n\\end{table}", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "0.6075", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 97 (MIT)" - }, - { - "id": "lpmilp-099-network-optimization", - "question": "In network communication services, bandwidth plays an important role. Below is a bandwidth communication table between several communication nodes, showing the bandwidth between any two nodes. If two nodes cannot be directly connected, the corresponding bandwidth is $0$. It is required to establish a link between node $A$ and node $E$ that must pass through service node $C$ (without loops). The bandwidth of this link is defined as the minimum bandwidth value on the link. Please propose a reasonable link arrangement to maximize the bandwidth of this link and find out the maximum bandwidth.\n\n\\begin{table}[h]\n \\centering\n \\begin{tabular}{|c|c|c|c|c|c|}\n \\hline\n & A & B & C & D & E \\\\\n \\hline\n A & 0 & 90 & 85 & 0 & 65 \\\\\n \\hline\n B & 95 & 0 & 70 & 65 & 34 \\\\\n \\hline\n C & 60 & 0 & 0 & 88 & 80 \\\\\n \\hline\n D & 67 & 30 & 25 & 0 & 84 \\\\\n \\hline\n E & 0 & 51 & 0 & 56 & 0 \\\\\n \\hline\n \\end{tabular}\n\\end{table}", - "expected_skill": "cuopt-numerical-optimization-api-python", - "expected_script": null, - "ground_truth": "84.0", - "expected_behavior": [ - "Reports an optimal objective value that exactly matches the ground_truth to the precision shown (no rounding tolerance is allowed)" - ], - "source": "microsoft/OptiGuide optimind_cleaned_classified_industryor.csv row 98 (MIT)" - } -] diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/resources/qp_examples.md b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/resources/qp_examples.md deleted file mode 100644 index 80b9802d..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python/resources/qp_examples.md +++ /dev/null @@ -1,198 +0,0 @@ -# QP: Python API Examples - -## Portfolio Optimization - -```python -""" -Minimize portfolio variance (risk): - minimize x^T * Q * x - subject to sum(x) = 1 (fully invested) - r^T * x >= target (minimum return) - x >= 0 (no short selling) - -Note: QP is beta and MUST use MINIMIZE (not MAXIMIZE) -""" -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings - -problem = Problem("Portfolio") - -# Portfolio weights (decision variables) -x1 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_a") -x2 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_b") -x3 = problem.addVariable(lb=0, ub=1, vtype=CONTINUOUS, name="stock_c") - -# Expected returns -r1, r2, r3 = 0.12, 0.08, 0.05 # 12%, 8%, 5% -target_return = 0.08 - -# Covariance matrix Q: -# [[0.04, 0.01, 0.005], -# [0.01, 0.02, 0.008], -# [0.005, 0.008, 0.01]] -# -# Quadratic objective: x^T * Q * x -# Expanded: 0.04*x1² + 0.02*x2² + 0.01*x3² + 2*0.01*x1*x2 + 2*0.005*x1*x3 + 2*0.008*x2*x3 - -problem.setObjective( - 0.04*x1*x1 + 0.02*x2*x2 + 0.01*x3*x3 + - 0.02*x1*x2 + 0.01*x1*x3 + 0.016*x2*x3, - sense=MINIMIZE # MUST be MINIMIZE for QP! -) - -# Linear constraints -problem.addConstraint(x1 + x2 + x3 == 1, name="budget") -problem.addConstraint(r1*x1 + r2*x2 + r3*x3 >= target_return, name="min_return") - -# Solve -settings = SolverSettings() -settings.set_parameter("time_limit", 60) -problem.solve(settings) - -# Results -if problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"Portfolio variance: {problem.ObjValue:.6f}") - print(f"Portfolio std dev: {problem.ObjValue**0.5:.4f}") - print(f"\nAllocation:") - print(f" Stock A: {x1.getValue()*100:.2f}%") - print(f" Stock B: {x2.getValue()*100:.2f}%") - print(f" Stock C: {x3.getValue()*100:.2f}%") - - actual_return = r1*x1.getValue() + r2*x2.getValue() + r3*x3.getValue() - print(f"\nExpected return: {actual_return*100:.2f}%") -``` - -## Least Squares - -```python -""" -Minimize ||Ax - b||² = (Ax-b)^T(Ax-b) - -Example: Find point closest to (3, 4) -minimize (x-3)² + (y-4)² = x² - 6x + 9 + y² - 8y + 16 -""" -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE -from cuopt.linear_programming.solver_settings import SolverSettings - -problem = Problem("LeastSquares") - -x = problem.addVariable(lb=-100, ub=100, vtype=CONTINUOUS, name="x") -y = problem.addVariable(lb=-100, ub=100, vtype=CONTINUOUS, name="y") - -# Quadratic objective: (x-3)² + (y-4)² -# Expanded: x² + y² - 6x - 8y + 25 -problem.setObjective( - x*x + y*y - 6*x - 8*y + 25, - sense=MINIMIZE -) - -result = problem.solve(SolverSettings()) - -if problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"x = {x.getValue():.4f}") # Should be ~3 - print(f"y = {y.getValue():.4f}") # Should be ~4 -else: - raise RuntimeError(f"Solver failed with status: {problem.Status.name}") -``` - -## Quadratic with Linear Constraints - -```python -""" -minimize x² + y² + z² -subject to x + y + z = 10 - x >= 0, y >= 0, z >= 0 -""" -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE - -problem = Problem("QuadraticConstrained") - -x = problem.addVariable(lb=0, vtype=CONTINUOUS, name="x") -y = problem.addVariable(lb=0, vtype=CONTINUOUS, name="y") -z = problem.addVariable(lb=0, vtype=CONTINUOUS, name="z") - -problem.setObjective(x*x + y*y + z*z, sense=MINIMIZE) -problem.addConstraint(x + y + z == 10) - -problem.solve() - -if problem.Status.name == "Optimal": - print(f"x = {x.getValue():.4f}") - print(f"y = {y.getValue():.4f}") - print(f"z = {z.getValue():.4f}") - print(f"Objective = {problem.ObjValue:.4f}") -``` - -## Maximization Workaround - -```python -""" -QP only supports MINIMIZE. -To maximize f(x), minimize -f(x). - -Example: maximize -x² + 4x (parabola with max at x=2) -""" -from cuopt.linear_programming.problem import Problem, CONTINUOUS, MINIMIZE - -problem = Problem("MaxWorkaround") - -x = problem.addVariable(lb=0, ub=10, vtype=CONTINUOUS, name="x") - -# Want to maximize: -x² + 4x -# Instead minimize: -(-x² + 4x) = x² - 4x -problem.setObjective(x*x - 4*x, sense=MINIMIZE) - -problem.solve() - -if problem.Status.name in ["Optimal", "PrimalFeasible"]: - print(f"x = {x.getValue():.4f}") # Should be 2 - print(f"Minimized value = {problem.ObjValue:.4f}") # Should be -4 - print(f"Original maximum = {-problem.ObjValue:.4f}") # Should be 4 -else: - print(f"Solver did not find optimal solution. Status: {problem.Status.name}") -``` - -## Expanding Covariance Matrix - -Given covariance matrix Q and weight vector x: - -```python -# Covariance matrix -Q = [ - [0.04, 0.01, 0.005], - [0.01, 0.02, 0.008], - [0.005, 0.008, 0.01] -] - -# Expansion: x^T * Q * x -# = Q[0,0]*x1² + Q[1,1]*x2² + Q[2,2]*x3² -# + 2*Q[0,1]*x1*x2 + 2*Q[0,2]*x1*x3 + 2*Q[1,2]*x2*x3 -# -# = 0.04*x1*x1 + 0.02*x2*x2 + 0.01*x3*x3 -# + 0.02*x1*x2 + 0.01*x1*x3 + 0.016*x2*x3 - -objective = ( - Q[0][0]*x1*x1 + Q[1][1]*x2*x2 + Q[2][2]*x3*x3 + - 2*Q[0][1]*x1*x2 + 2*Q[0][2]*x1*x3 + 2*Q[1][2]*x2*x3 -) -``` - -## Critical Reminders - -1. **MINIMIZE only** - solver rejects MAXIMIZE for QP -2. **Convexity** - Q should be positive semi-definite -3. **Beta status** - API may change in future versions -4. **Status checking** - use PascalCase: `"Optimal"` not `"OPTIMAL"` - ---- - -## Additional References (tested in CI) - -For more complete examples, read these files: - -| Example | File | Description | -|---------|------|-------------| -| Simple QP | `docs/cuopt/source/cuopt-python/lp-qp-milp/examples/simple_qp_example.py` | Basic QP setup | -| QP with Matrix | `docs/cuopt/source/cuopt-python/lp-qp-milp/examples/qp_matrix_example.py` | CSR matrix format for Q | - -These examples are tested by CI (`ci/test_doc_examples.sh`) and represent canonical usage. diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started b/plugins/nvidia-skills/skills/nemoclaw-user-get-started new file mode 120000 index 00000000..6b780fc1 --- /dev/null +++ b/plugins/nvidia-skills/skills/nemoclaw-user-get-started @@ -0,0 +1 @@ +../../../skills/NemoClaw/nemoclaw-user-get-started \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/SKILL.md b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/SKILL.md deleted file mode 100644 index 5b8c8c95..00000000 --- a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/SKILL.md +++ /dev/null @@ -1,353 +0,0 @@ ---- -name: "nemoclaw-user-get-started" -description: "Installs NemoClaw, launches a sandbox, and runs the first agent prompt. Use when onboarding, installing, or launching a NemoClaw sandbox for the first time. Trigger keywords - nemoclaw quickstart, install nemoclaw openclaw sandbox, nemohermes quickstart, hermes agent nemoclaw, run hermes openshell sandbox, nemoclaw prerequisites, nemoclaw supported platforms, nemoclaw hardware software, nemoclaw windows wsl2 setup, nemoclaw install windows docker desktop." ---- - - - - -# NemoClaw Quickstart with OpenClaw - -Follow these steps to get started with NemoClaw and your first sandboxed OpenClaw agent. - -**Note:** - -Make sure you have completed reviewing the Prerequisites (use the `nemoclaw-user-get-started` skill) before following this guide. - -## Install NemoClaw and Onboard OpenClaw Agent - -Download and run the installer script. -The script installs Node.js if it is not already present, then runs the guided onboard wizard to create a sandbox, configure inference, and apply security policies. - -**Note:** - -NemoClaw creates a fresh OpenClaw instance inside the sandbox during the onboarding process. - -```bash -curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash -``` - -The piped installer prompts through your terminal. In headless scripts or CI, -pass explicit acceptance to the `bash` side of the pipe: - -```console -$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | NEMOCLAW_NON_INTERACTIVE=1 NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 bash -``` - -If you use nvm or fnm to manage Node.js, the installer might not update your current shell's PATH. -If `nemoclaw` is not found after install, run `source ~/.bashrc` (or `source ~/.zshrc` for zsh) or open a new terminal. - -On Linux, the installer checks Docker before it installs NemoClaw. -If Docker is missing, the installer downloads the official Docker convenience script, asks for `sudo`, installs Docker, and starts the Docker service when systemd is available. -If Docker is installed but your current shell cannot use the Docker socket yet, the installer adds your user to the `docker` group when needed and exits with a recovery command. - -On macOS, the installer uses the Docker-driver OpenShell gateway path with Docker Desktop or Colima. - -```console -$ newgrp docker -$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash -``` - -On DGX Spark, DGX Station, and Windows WSL, an interactive installer offers express install after you accept the third-party software notice. -Express install switches onboarding to non-interactive mode, allows `sudo` password prompts for required host changes, applies the suggested security policy, and selects the managed local inference path for that platform. -On WSL, express install selects the Windows-host Ollama setup path. -Set `NEMOCLAW_NO_EXPRESS=1` to skip the express prompt, or set `NEMOCLAW_PROVIDER` before launching the installer when you want to choose a provider yourself. - -The installer auto-launches `nemoclaw onboard` when it can locate the freshly-installed binary. -If it cannot locate the binary, or if blocking host preflight checks fail, it does not launch the wizard automatically. -In that case, the installer prints the relevant diagnostics and a `To finish setup, run:` block with the explicit `nemoclaw onboard` command. - -**Note:** - -The onboard flow builds the sandbox image with `NEMOCLAW_DISABLE_DEVICE_AUTH=1` so the dashboard is immediately usable during setup. -This is a build-time setting baked into the sandbox image, not a runtime knob. -If you export `NEMOCLAW_DISABLE_DEVICE_AUTH` after onboarding finishes, it has no effect on an existing sandbox. - -### Respond to the Onboard Wizard - -After the installer launches `nemoclaw onboard`, the wizard runs preflight checks, starts or reuses the OpenShell gateway, and asks for an inference provider, sandbox name, optional web search, optional messaging channels, and network policy presets. -At any prompt, press Enter to accept the default shown in `[brackets]`, type `back` to return to the previous prompt, or type `exit` to quit. -If existing sandbox sessions are running, the installer warns before onboarding because the setup can rebuild or upgrade sandboxes after the new sandbox launches. - -The inference provider prompt presents a numbered list. - -```text - 1) NVIDIA Endpoints - 2) OpenAI - 3) Other OpenAI-compatible endpoint - 4) Anthropic - 5) Other Anthropic-compatible endpoint - 6) Google Gemini - 7) Local Ollama (localhost:11434) - 8) Model Router (experimental) - Choose [1]: -``` - -Pick the option that matches where you want inference traffic to go, then expand the matching helper below for the follow-up prompts and the API key environment variable to set. -For the full list of providers and validation behavior, refer to Inference Options (use the `nemoclaw-user-configure-inference` skill). -Local Ollama appears when NemoClaw detects a usable local Ollama path or can offer an install or start action for your platform. -The Model Router option appears when the blueprint router profile is enabled. - -**Tip:** - -Export the API key before launching the installer so the wizard does not have to ask for it. -For example, run `export NVIDIA_API_KEY=` before `curl ... | bash`. -If you entered a key incorrectly, refer to Reset a Stored Credential (use the `nemoclaw-user-manage-sandboxes` skill) to clear and re-enter it. - -**Option 1: NVIDIA Endpoints:** - -Routes inference to models hosted on [build.nvidia.com](https://build.nvidia.com). - -Use `NVIDIA_API_KEY` for the API key. Get one from the [NVIDIA build API keys page](https://build.nvidia.com/settings/api-keys). - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, press Enter (or type `1`) to select **NVIDIA Endpoints**. -2. At the `NVIDIA_API_KEY:` prompt, paste your key if it is not already exported. -3. At the `Choose model [1]:` prompt, pick a curated model from the list (for example, `Nemotron 3 Super 120B`, `GLM-5`, `MiniMax M2.7`, `GPT-OSS 120B`, or `DeepSeek V4 Pro`), or pick `Other...` to enter any model ID from the [NVIDIA Endpoints catalog](https://build.nvidia.com). - -NemoClaw validates the model against the catalog API before creating the sandbox. - -**Tip:** - -Use this option for Nemotron and other models hosted on `build.nvidia.com`. If you run NVIDIA Nemotron from a self-hosted NIM, an enterprise gateway, or any other endpoint, choose **Option 3** instead, since all Nemotron models expose OpenAI-compatible APIs. - -**Option 2: OpenAI:** - -Routes inference to the OpenAI API at `https://api.openai.com/v1`. - -Use `OPENAI_API_KEY` for the API key. Get one from the [OpenAI API keys page](https://platform.openai.com/api-keys). - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `2` to select **OpenAI**. -2. At the `OPENAI_API_KEY:` prompt, paste your key if it is not already exported. -3. At the `Choose model [1]:` prompt, pick a curated model (for example, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.4-nano`, or `gpt-5.4-pro-2026-03-05`), or pick **Other...** to enter any OpenAI model ID. - -**Option 3: Other OpenAI-Compatible Endpoint:** - -Routes inference to any server that implements `/v1/chat/completions`, including OpenRouter, LocalAI, llama.cpp, vLLM behind a proxy, and any compatible gateway. - -Use `COMPATIBLE_API_KEY` for the API key. Set it to whatever credential your endpoint expects. If your endpoint does not require auth, use any non-empty placeholder. - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `3` to select **Other OpenAI-compatible endpoint**. -2. At the `OpenAI-compatible base URL` prompt, enter the provider's base URL. Find the exact value in your provider's API documentation. NemoClaw appends `/v1` automatically, so leave that suffix off. -3. At the `COMPATIBLE_API_KEY:` prompt, paste your key if it is not already exported. -4. At the `Other OpenAI-compatible endpoint model []:` prompt, enter the model ID exactly as it appears in your provider's model catalog. - -For example, when you use NVIDIA's OpenAI-compatible inference endpoint, enter `https://inference-api.nvidia.com` as the base URL and the model ID your endpoint exposes, such as `openai/openai/gpt-5.5`. - -NemoClaw sends a real inference request to validate the endpoint and model. -If the endpoint does not return the streaming events OpenClaw needs from the Responses API, NemoClaw falls back to the chat completions API and configures OpenClaw to use `openai-completions`. - -**Tip:** - -NVIDIA Nemotron models expose OpenAI-compatible APIs, so this option is the right choice for any Nemotron deployment that does not live on `build.nvidia.com`. Common examples include a self-hosted NIM container, an enterprise NVIDIA AI Enterprise gateway, or a vLLM/SGLang server running Nemotron weights. Point the base URL at your endpoint and enter the Nemotron model ID exactly as your server reports it. - -**Option 4: Anthropic:** - -Routes inference to the Anthropic Messages API at `https://api.anthropic.com`. - -Use `ANTHROPIC_API_KEY` for the API key. Get one from the [Anthropic console keys page](https://console.anthropic.com/settings/keys). - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `4` to select **Anthropic**. -2. At the `ANTHROPIC_API_KEY:` prompt, paste your key if it is not already exported. -3. At the `Choose model [1]:` prompt, pick a curated model (for example, `claude-sonnet-4-6`, `claude-haiku-4-5`, or `claude-opus-4-6`), or pick **Other...** to enter any Claude model ID. - -**Option 5: Other Anthropic-Compatible Endpoint:** - -Routes inference to any server that implements the Anthropic Messages API at `/v1/messages`, including Claude proxies, Bedrock-compatible gateways, and self-hosted Anthropic-compatible servers. - -Use `COMPATIBLE_ANTHROPIC_API_KEY` for the API key. Set it to whatever credential your endpoint expects. - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `5` to select **Other Anthropic-compatible endpoint**. -2. At the `Anthropic-compatible base URL` prompt, enter the proxy or gateway's base URL from its documentation. -3. At the `COMPATIBLE_ANTHROPIC_API_KEY:` prompt, paste your key if it is not already exported. -4. At the `Other Anthropic-compatible endpoint model []:` prompt, enter the model ID exactly as it appears in your gateway's model catalog. - -**Option 6: Google Gemini:** - -Routes inference to Google's OpenAI-compatible Gemini endpoint at `https://generativelanguage.googleapis.com/v1beta/openai/`. - -Use `GEMINI_API_KEY` for the API key. Get one from [Google AI Studio API keys](https://aistudio.google.com/app/apikey). - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `6` to select **Google Gemini**. -2. At the `GEMINI_API_KEY:` prompt, paste your key if it is not already exported. -3. At the `Choose model [5]:` prompt, pick a curated model (for example, `gemini-3.1-pro-preview`, `gemini-3.1-flash-lite-preview`, `gemini-3-flash-preview`, `gemini-2.5-pro`, `gemini-2.5-flash`, or `gemini-2.5-flash-lite`), or pick **Other...** to enter any Gemini model ID. - -**Option 7: Local Ollama:** - -Routes inference to a local Ollama instance. Depending on your platform, the wizard can use an existing daemon, start an installed daemon, or offer an install action. - -No API key is required. On non-WSL hosts, NemoClaw generates a token and starts an authenticated proxy so containers can reach Ollama without exposing the daemon directly to your network. -On WSL, NemoClaw can also use Ollama on the Windows host through `host.docker.internal`. - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `7` to select **Local Ollama**. -2. At the `Choose model [1]:` prompt, pick from **Ollama models** if any are already installed. If none are installed, pick a **starter model** to pull and load now, or pick **Other...** to enter any Ollama model ID. - -For setup details, including GPU recommendations and starter model choices, refer to Use a Local Inference Server (use the `nemoclaw-user-configure-inference` skill). - -**Option 8: Model Router:** - -Starts a host-side model router and routes sandbox inference through OpenShell to that router. -The router chooses from the model pool in `nemoclaw-blueprint/router/pool-config.yaml` for each request. - -Use `NVIDIA_API_KEY` for the model pool credentials. - -Respond to the wizard as follows. - -1. At the `Choose [1]:` prompt, type `8` to select **Model Router (experimental)**. -2. At the `NVIDIA_API_KEY:` prompt, paste your key if it is not already exported. -3. Review the configuration summary and continue with the sandbox build. - -For scripted setup, set: - -```console -$ NEMOCLAW_PROVIDER=routed NVIDIA_API_KEY= nemoclaw onboard --non-interactive -``` - -The router listens on the host at port `4000`. -The sandbox still calls `https://inference.local/v1`, so do not point in-sandbox tools at the host router port directly. - -**Local NIM and Local vLLM:** - -- **Local NVIDIA NIM** appears when `NEMOCLAW_EXPERIMENTAL=1` is set and the host has a NIM-capable GPU. NemoClaw pulls and manages a NIM container. -- **Local vLLM (already running)** appears whenever NemoClaw detects a vLLM server on `localhost:8000`. No flag is required for the menu entry. NemoClaw auto-detects the loaded model. -- **Local vLLM (managed install/start)** appears by default on DGX Spark and DGX Station. Generic Linux NVIDIA GPU hosts require `NEMOCLAW_EXPERIMENTAL=1` or `NEMOCLAW_PROVIDER=install-vllm`. NemoClaw pulls and starts a vLLM container on supported hosts. - -For setup, refer to Use a Local Inference Server (use the `nemoclaw-user-configure-inference` skill). - -### Review the Configuration Before the Sandbox Build - -After you enter the sandbox name, the wizard prints a review summary and asks for final confirmation before registering the provider, prompting for optional integrations, and building the sandbox image. -For example, if you picked an OpenAI-compatible endpoint, the summary looks like the following: - -```text - ────────────────────────────────────────────────── - Review configuration - ────────────────────────────────────────────────── - Provider: compatible-endpoint - Model: openai/openai/gpt-5.5 - API key: COMPATIBLE_API_KEY (staged for OpenShell gateway registration) - Web search: disabled - Messaging: none - Sandbox name: my-gpt-claw - Note: Sandbox build typically takes 5–15 minutes on this host. - ────────────────────────────────────────────────── - Web search and messaging channels will be prompted next. - Apply this configuration? [Y/n]: -``` - -The default is `Y`, so you can press Enter once to continue. Answer `n` to abort cleanly, fix the entries, and re-run `nemoclaw onboard`. - -Non-interactive runs (`NEMOCLAW_NON_INTERACTIVE=1`) print the summary for log clarity but skip the prompt. - -### Configure Web Search and Messaging - -After you confirm the summary, NemoClaw registers the selected provider with the OpenShell gateway and sets the `inference.local` route. -The wizard then asks whether to enable Brave Web Search. -If you enable it, enter a Brave Search API key when prompted. - -The wizard also offers messaging channels such as Telegram, Discord, Slack, and WhatsApp. -Press a channel number to toggle it, then press Enter to continue. -If you select a channel, NemoClaw validates the token format before it bakes the channel configuration into the sandbox. -For example, Slack bot tokens must start with `xoxb-`. - -### Choose Network Policy Presets - -After the sandbox image builds and OpenClaw starts inside the sandbox, NemoClaw asks which network policy tier to apply. -The default **Balanced** tier includes common development presets such as npm, PyPI, Hugging Face, Homebrew, and Brave Search when the selected agent supports web search. -Use the arrow keys or `j` and `k` to move, Space to select, and Enter to confirm. - -The preset selector lets you include more destinations, such as GitHub, Jira, Slack, Telegram, or local inference. -Press `r` to toggle a selected preset between read-only and read-write when the preset supports both modes. - -When the install completes, a summary confirms the running environment. -Before printing the summary, NemoClaw verifies that the sandbox gateway and dashboard port forward are reachable. -Inference route and messaging bridge checks are reported as warnings when they need more time or additional configuration. -The `Model` and provider line reflects the inference option you picked during onboarding. -The example below shows the result if you picked an OpenAI-compatible endpoint during onboarding. - -```text -────────────────────────────────────────────────── -NemoClaw is ready - -Sandbox: my-gpt-claw -Model: openai/openai/gpt-5.5 (Other OpenAI-compatible endpoint) - -Start chatting - - Browser: - http://127.0.0.1:18789/ - - Terminal: - nemoclaw my-gpt-claw connect - then run: openclaw tui - -Authenticated dashboard URL, if needed: - nemoclaw my-gpt-claw dashboard-url --quiet - -Manage later - - Status: nemoclaw my-gpt-claw status - Logs: nemoclaw my-gpt-claw logs --follow - Model: nemoclaw inference set --model --provider --sandbox my-gpt-claw - Policies: nemoclaw my-gpt-claw policy-add - Credentials: nemoclaw credentials reset && nemoclaw onboard -────────────────────────────────────────────────── - -[INFO] === Installation complete === -``` - -If you picked a different option, the `Model` line shows that provider's model and label instead. For example, you might see `gpt-5.4 (OpenAI)`, `claude-sonnet-4-6 (Anthropic)`, `gemini-2.5-flash (Google Gemini)`, `llama3.1:8b (Local Ollama)`, `nvidia-routed (Model Router)`, or ` (Other OpenAI-compatible endpoint)`. - -## Run Your First Agent Prompt - -You can chat with the agent from the terminal or the browser. - -### Open the OpenClaw UI in a Browser to Chat with the Agent - -The onboard wizard starts a background port forward to the sandbox dashboard, then prints the dashboard URL in the install summary. -The default host port is `18789`. -If that port is already taken, NemoClaw uses the next free dashboard port, such as `18790`, and prints that port in the final URL. -If the chosen port becomes occupied after the sandbox build starts, onboarding rolls back the newly-created sandbox and asks you to retry instead of printing an unreachable dashboard URL. -The install transcript does not print the gateway token. -If the browser requires authentication, use the `dashboard-url --quiet` command to print a complete URL explicitly. - -```text -nemoclaw my-gpt-claw dashboard-url --quiet -``` - -Open the dashboard URL in your browser. -If the browser asks for authentication, run `nemoclaw my-gpt-claw dashboard-url --quiet` and open the returned URL. -Treat the authenticated URL like a password. - -### Chat with the Agent from the Terminal - -Connect to the sandbox and use the OpenClaw CLI. - -```bash -nemoclaw my-assistant connect -# inside the sandbox: -openclaw tui -``` - -## References - -- **Load [references/quickstart-hermes.md](references/quickstart-hermes.md)** when users ask for Hermes setup, NemoHermes onboarding, or running Hermes inside OpenShell. Installs NemoClaw, selects the Hermes agent, and launches a sandboxed Hermes API endpoint. -- **Load [references/prerequisites.md](references/prerequisites.md)** when verifying prerequisites before installation. Lists the hardware, software, and container runtime requirements for running NemoClaw. -- **Load [references/windows-preparation.md](references/windows-preparation.md)** when preparing a Windows machine for NemoClaw, enabling WSL 2, configuring Docker Desktop for Windows, or troubleshooting a Windows-specific install error. Covers Windows-only preparation steps required before the Quickstart. - -## Related Skills - -- `nemoclaw-user-overview` — NemoClaw Overview (use the `nemoclaw-user-overview` skill) to learn what NemoClaw is and its capabilities diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/prerequisites.md b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/prerequisites.md deleted file mode 100644 index 2f3c781f..00000000 --- a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/prerequisites.md +++ /dev/null @@ -1,62 +0,0 @@ - - -# Prerequisites - -Before getting started, check the prerequisites to ensure you have the necessary software and hardware to run NemoClaw. - -## Hardware - -| Resource | Minimum | Recommended | -|----------|----------------|------------------| -| CPU | 4 vCPU | 4+ vCPU | -| RAM | 8 GB | 16 GB | -| Disk | 20 GB free | 40 GB free | - -The sandbox image is approximately 2.4 GB compressed. During image push, the Docker daemon, k3s, and the OpenShell gateway run alongside the export pipeline. The pipeline buffers decompressed layers in memory. On machines with less than 8 GB of RAM, this combined usage can trigger the OOM killer. If you cannot add memory, configuring at least 8 GB of swap can work around the issue at the cost of slower performance. - -## Software - -| Dependency | Version | -|------------|----------------------------------| -| Node.js | 22.16 or later | -| npm | 10 or later | -| Docker | Docker Engine, Docker Desktop, or Colima on a tested platform | -| Platform | See [Platforms](#platforms) below | - -On Linux, the installer can install Docker, start the Docker service, and add your user to the `docker` group. -If the group change is not active in the current shell, the installer exits with `newgrp docker` guidance before it starts onboarding. -If you choose the native Linux Ollama install path, the onboard wizard also requires `zstd` for Ollama archive extraction. - -On Debian and Ubuntu, NemoClaw installs `zstd` with `apt-get` if it is missing; on other Linux distributions, install `zstd` before onboarding. - -On macOS, NemoClaw uses the Docker-driver OpenShell gateway path with Docker Desktop or Colima. -You do not need to install or sign a separate OpenShell VM driver helper for standard macOS onboarding. - -**OpenShell Lifecycle:** - -For NemoClaw-managed environments, use `nemoclaw onboard` when you need to create or recreate the OpenShell gateway or sandbox. -Avoid `openshell self-update`, `npm update -g openshell`, `openshell gateway start --recreate`, or `openshell sandbox create` directly unless you intend to manage OpenShell separately and then rerun `nemoclaw onboard`. - -**Docker storage driver:** - -On Linux hosts running Docker 26 or later with the [containerd image store](https://docs.docker.com/engine/storage/containerd/) enabled (the install-time default for fresh `docker-ce` installations on Ubuntu 24.04 and similar distros), `nemoclaw onboard` transparently builds a `fuse-overlayfs`-enabled cluster image to bypass a kernel-level nested-overlay limitation in k3s. -No manual setup is required. -See the troubleshooting guide (use the `nemoclaw-user-reference` skill) for the override knobs and a manual `daemon.json` alternative. - -## Platforms - -The following table lists tested platform and runtime combinations. -Availability is not limited to these entries, but untested configurations can have issues. -The table is generated from [`ci/platform-matrix.json`](https://github.com/NVIDIA/NemoClaw/blob/main/ci/platform-matrix.json), the single source of truth kept in sync by CI and QA. - -| OS | Container runtime | Status | Notes | -|----|-------------------|--------|-------| -| Linux | Docker | Tested | Primary tested path. | -| macOS (Apple Silicon) | Colima, Docker Desktop | Tested with limitations | Install Xcode Command Line Tools (`xcode-select --install`) and start the runtime before running the installer. | -| DGX Spark | Docker | Tested | Use the standard installer and `nemoclaw onboard`. For an end-to-end walkthrough with local Ollama inference, see the [NVIDIA Spark playbook](https://build.nvidia.com/spark/nemoclaw). | -| Windows WSL2 | Docker Desktop (WSL backend) | Tested with limitations | Requires WSL2 with Docker Desktop backend. | - -## Next Steps - -- Prepare Windows for NemoClaw (use the `nemoclaw-user-get-started` skill) if you are using Windows. -- Quickstart (use the `nemoclaw-user-get-started` skill) to install NemoClaw and launch your first sandbox. diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/quickstart-hermes.md b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/quickstart-hermes.md deleted file mode 100644 index b658f367..00000000 --- a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/quickstart-hermes.md +++ /dev/null @@ -1,170 +0,0 @@ - - -# NemoClaw Quickstart with Hermes - -Use NemoHermes when you want NemoClaw to create an OpenShell sandbox that runs Hermes instead of the default OpenClaw agent. -The `nemohermes` command is an alias for `nemoclaw` with the Hermes agent pre-selected. - -**Experimental Feature:** - -The Hermes agent option is experimental. -Interfaces, defaults, and supported features may change without notice, and it is not recommended for production use. - -Review the Prerequisites (use the `nemoclaw-user-get-started` skill) before starting. -The first Hermes build can take several minutes because NemoClaw builds the Hermes sandbox base image if it is not already cached. - -## Install and Onboard - -Start the installer with `NEMOCLAW_AGENT=hermes` set in your shell. -The installer installs the CLI, selects the `nemohermes` alias, and runs the guided onboarding flow. - -```console -$ export NEMOCLAW_AGENT=hermes -$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash -``` - -If NemoClaw is already installed, start Hermes onboarding directly. - -```console -$ nemohermes onboard -``` - -## Respond to the Wizard - -The onboard wizard asks for a sandbox name, inference provider, model, credentials, and network policy preset. -At any prompt, press Enter to accept the default shown in `[brackets]`, type `back` to return to the previous prompt, or type `exit` to quit. - -The default Hermes sandbox name is `hermes`. -Use a distinct sandbox name, such as `my-hermes`, so you can run Hermes and OpenClaw sandboxes side by side. -NemoClaw prevents same-name reuse when an existing sandbox uses a different agent. - -```text -Sandbox name [hermes]: my-hermes -``` - -Choose the inference provider that matches where you want Hermes model traffic to go. -The provider options and credential environment variables are the same as the standard NemoClaw quickstart. -For provider-specific prompts, refer to the Respond to the Onboard Wizard (use the `nemoclaw-user-get-started` skill) section and the Inference Options (use the `nemoclaw-user-configure-inference` skill) page. -The Hermes wizard does not ask for Brave Web Search because Hermes does not use NemoClaw's OpenClaw web-search configuration. - -After provider and policy selection, review the summary and confirm the build. -NemoClaw writes Hermes configuration into `/sandbox/.hermes`, routes model traffic through `inference.local`, and starts the Hermes gateway inside the sandbox. -The Hermes image includes runtime dependencies for the supported NemoClaw messaging integrations, API service, and health endpoint. -The base image does not include unsupported Hermes integrations. - -**Note:** - -Hermes uses an agent-specific baseline policy that allows the Hermes binary and Python runtime to reach the required Nous Research service endpoints, PyPI, NVIDIA inference endpoints, and selected messaging APIs. - -## Use Non-Interactive Setup - -For CI or scripted installs, set the required environment variables before running the installer. -The example below uses NVIDIA Endpoints and creates a sandbox named `my-hermes`. - -```console -$ export NEMOCLAW_AGENT=hermes -$ export NEMOCLAW_NON_INTERACTIVE=1 -$ export NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1 -$ export NEMOCLAW_SANDBOX_NAME=my-hermes -$ export NVIDIA_API_KEY= -$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash -``` - -Use the provider variables from Inference Options (use the `nemoclaw-user-configure-inference` skill) when you choose a different provider. - -## Connect to Hermes - -When onboarding completes, NemoClaw prints the sandbox name, model, lifecycle commands, and Hermes API endpoint. -Hermes exposes an OpenAI-compatible API on port `8642`, not a browser dashboard. - -```text -────────────────────────────────────────────────── -NemoHermes is ready - -Sandbox: my-hermes -Model: nvidia/nemotron-3-super-120b-a12b (NVIDIA Endpoints) - -Access - - Hermes Agent OpenAI-compatible API - Port 8642 must be forwarded before connecting. - http://127.0.0.1:8642/v1 - -Terminal: - nemohermes my-hermes connect - -Manage later - - Status: nemohermes my-hermes status - Logs: nemohermes my-hermes logs --follow - Model: nemohermes inference set --model --provider --sandbox my-hermes - Policies: nemohermes my-hermes policy-add - Credentials: nemohermes credentials reset && nemohermes onboard -────────────────────────────────────────────────── -``` - -To chat with the agent from a terminal, follow these steps: - -1. Connect to the sandbox and start the Hermes CLI. - - ```console - $ nemohermes my-hermes connect - ``` - -2. Inside the sandbox, run the Hermes CLI. - - ```console - $ hermes - ``` - -## Check the API Endpoint - -The onboard flow starts the port forward automatically. -Check the health endpoint from the host to confirm that the Hermes API is reachable. - -```console -$ curl -sf http://127.0.0.1:8642/health -``` - -If the command cannot connect after a reboot or terminal restart, start the forward again. - -```console -$ openshell forward start --background 8642 my-hermes -``` - -Configure an OpenAI-compatible client with the base URL `http://127.0.0.1:8642/v1`. -Hermes uses API header authentication for client requests. -Do not append an OpenClaw `#token=` URL fragment to the Hermes endpoint. - -## Manage the Sandbox - -Use the same lifecycle commands as a standard NemoClaw sandbox. -The `nemohermes` alias keeps help text and recovery messages aligned with Hermes, while targeting the same registered sandbox. -`nemoclaw list` shows the agent type for each sandbox so you can distinguish Hermes and OpenClaw entries. - -```console -$ nemohermes my-hermes status -$ nemohermes my-hermes logs --follow -$ nemohermes my-hermes snapshot create --name before-change -$ nemohermes my-hermes rebuild -``` - -To change the active model or provider without rebuilding the sandbox, use `nemohermes inference set`. -It updates the OpenShell inference route and patches `/sandbox/.hermes/config.yaml` without restarting Hermes. - -```console -$ nemohermes inference set --model --provider -``` - -To remove the sandbox when you are done, destroy it explicitly. - -```console -$ nemohermes my-hermes destroy -``` - -## Next Steps - -- Inference Options (use the `nemoclaw-user-configure-inference` skill) to choose a provider and model. -- Commands (use the `nemoclaw-user-reference` skill) to see the full `nemohermes` alias behavior. -- Backup and Restore (use the `nemoclaw-user-manage-sandboxes` skill) to preserve sandbox state before destructive operations. -- Monitor Sandbox Activity (use the `nemoclaw-user-monitor-sandbox` skill) to inspect OpenShell events and sandbox logs. diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/windows-preparation.md b/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/windows-preparation.md deleted file mode 100644 index 6b99632a..00000000 --- a/plugins/nvidia-skills/skills/nemoclaw-user-get-started/references/windows-preparation.md +++ /dev/null @@ -1,136 +0,0 @@ - - -# Prepare Windows for NemoClaw - -You can run NemoClaw inside Windows Subsystem for Linux (WSL 2) on Windows. -Complete these steps before following the Quickstart (use the `nemoclaw-user-get-started` skill). -Linux and macOS users do not need this page and can go directly to the Quickstart. - -**Note:** - -This guide has been tested on x86-64. - -## Prerequisites - -Verify the following before you begin: - -- Windows 10 (build 19041 or later) or Windows 11. -- Hardware requirements are the same as the Quickstart (use the `nemoclaw-user-get-started` skill). - -## Option: Use the Bootstrap Script - -Open Windows PowerShell on the Windows host and run the bootstrap script: - -```console -$ Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/NVIDIA/NemoClaw/main/scripts/bootstrap-windows.ps1' -OutFile "$env:TEMP\bootstrap-windows.ps1"; powershell.exe -ExecutionPolicy Bypass -File "$env:TEMP\bootstrap-windows.ps1" -``` - -The command downloads the script to a temporary file before running it. -`-ExecutionPolicy Bypass` applies only to that PowerShell process and avoids local policy blocking the downloaded script. -Run it from Windows, not from inside WSL. -The script requests Administrator privileges when needed, enables the required WSL 2 Windows features, installs or opens Ubuntu, and installs and starts Docker Desktop. -If Ubuntu is already registered, the script confirms it uses WSL 2, converts it from WSL 1 when needed, and verifies Docker is reachable from WSL. -If Windows requires a reboot after enabling WSL features, the script prompts for the reboot and registers a one-time continuation for the next sign-in. -If Docker Desktop shows first-run prompts, complete them and return to the PowerShell window. - -For advanced options, download the script first and run `Get-Help "$env:TEMP\bootstrap-windows.ps1" -Detailed`. -Useful parameters include `-DistroName`, `-InstallerUrl`, `-InstallerArgs`, and `-InstallDockerDesktop`. - -The bootstrap script does not install NemoClaw itself. -When Windows preparation is complete, it opens Ubuntu and prints the standard installer command to run inside Ubuntu: - -```console -$ curl -fsSL https://www.nvidia.com/nemoclaw.sh | bash -``` - -If the bootstrap script reports that Docker is not reachable from Ubuntu, open Docker Desktop Settings and confirm that WSL integration is enabled for Ubuntu (Settings > Resources > WSL integration), then rerun the script. - -The manual steps below describe the same Windows preparation pieces and are useful when you need to verify or repair WSL, Ubuntu, or Docker Desktop by hand. - -## Enable WSL 2 - -Open an elevated PowerShell (Run as Administrator): - -```console -$ wsl --install --no-distribution -``` - -This enables both the Windows Subsystem for Linux and Virtual Machine Platform features. - -Reboot if prompted. - -## Install and Register Ubuntu - -After reboot, open an elevated PowerShell again: - -```console -$ wsl --install -d Ubuntu -``` - -Let the distribution launch and complete first-run setup (pick a Unix username and password), then type `exit` to return to PowerShell. - -**Warning:** - -Do not use the `--no-launch` flag. -The `--no-launch` flag downloads the package but does not register the distribution with WSL. -Commands like `wsl -d Ubuntu` fail with "There is no distribution with the supplied name" until the distribution has been launched at least once. - -Verify the distribution is registered and running WSL 2: - -```console -$ wsl -l -v -``` - -Expected output: - -```text - NAME STATE VERSION -* Ubuntu Running 2 -``` - -## Install Docker Desktop - -Install [Docker Desktop](https://www.docker.com/products/docker-desktop/) with the WSL 2 backend (the default on Windows 11). - -After installation, open Docker Desktop Settings and confirm that WSL integration is enabled for your Ubuntu distribution (Settings > Resources > WSL integration). - -Verify from inside WSL: - -```console -$ wsl -$ docker info -``` - -`docker info` prints server information. -If you see "Cannot connect to the Docker daemon", confirm that Docker Desktop is running and that WSL integration is enabled. - -## Set Up Local Inference with Ollama (Optional) - -If you plan to select Ollama as your inference provider during onboarding, use one Ollama instance that WSL can reach. -You can install Ollama inside WSL yourself: - -```console -$ curl -fsSL https://ollama.com/install.sh | sh -``` - -If Ollama is installed but not already running in WSL, the onboarding process starts it for you. -You can also start it yourself beforehand with `ollama serve`. - -You can also use Ollama for Windows. -During onboarding, NemoClaw can use an already-running Windows-host daemon, start or restart an installed daemon, or install Ollama on the Windows host. -If the installer offers express install on WSL, accepting it selects this Windows-host Ollama path automatically. -When Ollama runs on the Windows host, NemoClaw detects it from WSL through `host.docker.internal` and pulls missing models through the Ollama HTTP API. -Do not run both the Windows and WSL Ollama instances on port `11434` at the same time. -Use one instance, or move one of them to a different port before running `nemoclaw onboard`. - -## Next Step - -Your Windows environment is ready. -If you used the bootstrap script, follow the installer command it printed inside Ubuntu. -If you prepared Windows manually, open a WSL terminal (type `wsl` in PowerShell, or open Ubuntu from Windows Terminal) and continue with the Quickstart (use the `nemoclaw-user-get-started` skill) to install NemoClaw and launch your first sandbox. - -All NemoClaw commands run inside WSL, not in PowerShell. - -## Troubleshooting - -For Windows-specific troubleshooting, refer to the Windows Subsystem for Linux section (use the `nemoclaw-user-reference` skill) in the Troubleshooting guide. From 042599e16b781641006085c6265a710d10545e0c Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 16:56:09 -0400 Subject: [PATCH 06/11] docs: refresh build-plugins.py header to describe both skill_files modes The module docstring still claimed skills/ was always materialized as relative symlinks. Update it to describe the `skill_files: copy | symlink` choice (default `copy`), and refresh the curated-plugin docstring to match. No behavior change. Signed-off-by: Jason Dudash --- .github/scripts/build-plugins.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/.github/scripts/build-plugins.py b/.github/scripts/build-plugins.py index 8f5f4dbc..1d6a8441 100755 --- a/.github/scripts/build-plugins.py +++ b/.github/scripts/build-plugins.py @@ -11,27 +11,35 @@ plugins.d/.yml Catalog plugin spec. Drives full regeneration of plugins// - (skills/ symlinks, .claude-plugin/plugin.json, .codex-plugin/plugin.json) + (skills/ tree, .claude-plugin/plugin.json, .codex-plugin/plugin.json) and its entry in both marketplace.json files. plugins//.skills-manifest.yml Per-plugin skill manifest for hand-curated plugins. Only the skills/ - symlink tree is materialized; plugin.jsons, assets, README, and the - marketplace entry stay hand-edited. + tree is rebuilt; plugin.jsons, assets, README, and the marketplace + entry stay hand-edited. plugins//assets/ Hand-maintained logo/image assets. plugins//README.md Optional plugin-specific notes. Generated outputs (committed): - plugins//skills// Symlink → ../../../skills// + plugins//skills// Real dir or symlink (see below) plugins//.claude-plugin/plugin.json (catalog plugins only) plugins//.codex-plugin/plugin.json (catalog plugins only) .claude-plugin/marketplace.json (catalog plugin entries; others preserved) .agents/plugins/marketplace.json (catalog plugin entries; others preserved) -The skills/ tree is materialized as RELATIVE symlinks, not file copies. The -canonical SKILL.md lives only under skills///; plugins/ -references it via symlink so the plugin tree stays in sync automatically. +How the skills/ tree gets populated is selected by `skill_files:` in +plugins.d/.yml (defaults to `copy` via plugins.d/_defaults.yml): + + copy rsync each curated skill into plugins//skills//. + Real files. Required for `codex plugin add` (Codex 0.132 + silently drops symlinks during install). + symlink Relative symlink plugins//skills/ → + ../../../skills//. No duplicated SKILL.md; + the plugin tree stays in sync with the canonical catalog + automatically. Works for `claude plugin install` and + `npx skills add`. NOT compatible with Codex local install. Usage: build-plugins.py Build everything. @@ -328,8 +336,9 @@ def build_catalog_plugin(spec: dict[str, Any]) -> str: def build_curated_plugin(plugin_dir: Path) -> str: """ A curated plugin is one with plugins//.skills-manifest.yml but - no plugins.d/.yml. We materialize only its skills/ tree (as - symlinks) and trust everything else to be hand-maintained. + no plugins.d/.yml. We rebuild only its skills/ tree (mode + selected by `skill_files:` in the manifest, default `copy`) and + trust everything else to be hand-maintained. """ manifest_path = plugin_dir / ".skills-manifest.yml" spec = read_yaml(manifest_path) From 8a94c27ea70bf56235708b2bb544b94c1a28cc58 Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 16:58:50 -0400 Subject: [PATCH 07/11] chore(plugins): repoint nvidia-skills curation after upstream sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream's daily skills sync (7946eaa) reorganized skills/cuopt/ and removed skills/NemoClaw/ entirely. The previous three curated entries in plugins.d/nvidia-skills.yml were all broken: - skills/cuopt/cuopt-install/ → removed upstream - skills/cuopt/cuopt-numerical-optimization-api-python/ → split into api-c / api-cli / server-api-python (no Python LP wrapper anymore) - skills/NemoClaw/nemoclaw-user-get-started/ → entire NemoClaw directory removed Repoint the plugin at a single still-present skill, skills/cuopt/cuopt-routing-api-python, so the build resolves and the plugin ships symlinks consumers can actually follow. Wider re-curation (adding more cuopt-* skills, restoring NemoClaw when it returns upstream) deferred to a follow-up. Signed-off-by: Jason Dudash --- plugins.d/nvidia-skills.yml | 4 +--- plugins/nvidia-skills/skills/cuopt-install | 1 - .../skills/cuopt-numerical-optimization-api-python | 1 - plugins/nvidia-skills/skills/cuopt-routing-api-python | 1 + plugins/nvidia-skills/skills/nemoclaw-user-get-started | 1 - 5 files changed, 2 insertions(+), 6 deletions(-) delete mode 120000 plugins/nvidia-skills/skills/cuopt-install delete mode 120000 plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python create mode 120000 plugins/nvidia-skills/skills/cuopt-routing-api-python delete mode 120000 plugins/nvidia-skills/skills/nemoclaw-user-get-started diff --git a/plugins.d/nvidia-skills.yml b/plugins.d/nvidia-skills.yml index b7870e9e..e055a304 100644 --- a/plugins.d/nvidia-skills.yml +++ b/plugins.d/nvidia-skills.yml @@ -25,9 +25,7 @@ default_prompts: # Reproduced under plugins//skills// in the form # selected by `skill_files:` (defined in plugins.d/_defaults.yml). include_skills: - - skills/cuopt/cuopt-numerical-optimization-api-python/ - - skills/cuopt/cuopt-install/ - - skills/NemoClaw/nemoclaw-user-get-started/ + - skills/cuopt/cuopt-routing-api-python/ # Override default (`copy`) → ship symlinks to ../../../skills/<...>/. # No duplicated SKILL.md, plugin tree stays in sync automatically. diff --git a/plugins/nvidia-skills/skills/cuopt-install b/plugins/nvidia-skills/skills/cuopt-install deleted file mode 120000 index 71ef5d4b..00000000 --- a/plugins/nvidia-skills/skills/cuopt-install +++ /dev/null @@ -1 +0,0 @@ -../../../skills/cuopt/cuopt-install \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python b/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python deleted file mode 120000 index 9669719b..00000000 --- a/plugins/nvidia-skills/skills/cuopt-numerical-optimization-api-python +++ /dev/null @@ -1 +0,0 @@ -../../../skills/cuopt/cuopt-numerical-optimization-api-python \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python b/plugins/nvidia-skills/skills/cuopt-routing-api-python new file mode 120000 index 00000000..68ae9452 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python @@ -0,0 +1 @@ +../../../skills/cuopt/cuopt-routing-api-python \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/nemoclaw-user-get-started b/plugins/nvidia-skills/skills/nemoclaw-user-get-started deleted file mode 120000 index 6b780fc1..00000000 --- a/plugins/nvidia-skills/skills/nemoclaw-user-get-started +++ /dev/null @@ -1 +0,0 @@ -../../../skills/NemoClaw/nemoclaw-user-get-started \ No newline at end of file From e324005b0a9d37442f8093831e181110b466c8b2 Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 17:02:10 -0400 Subject: [PATCH 08/11] chore(plugins): add cuopt-user-rules to nvidia-skills curation Append skills/cuopt/cuopt-user-rules to include_skills so the plugin ships base end-user guidance (covers install / routing / LP / MILP / QP / server) alongside the existing cuopt-routing-api-python skill. Trailing-slash also normalized for consistency. Signed-off-by: Jason Dudash --- plugins.d/nvidia-skills.yml | 1 + plugins/nvidia-skills/skills/cuopt-user-rules | 1 + 2 files changed, 2 insertions(+) create mode 120000 plugins/nvidia-skills/skills/cuopt-user-rules diff --git a/plugins.d/nvidia-skills.yml b/plugins.d/nvidia-skills.yml index e055a304..1b043144 100644 --- a/plugins.d/nvidia-skills.yml +++ b/plugins.d/nvidia-skills.yml @@ -26,6 +26,7 @@ default_prompts: # selected by `skill_files:` (defined in plugins.d/_defaults.yml). include_skills: - skills/cuopt/cuopt-routing-api-python/ + - skills/cuopt/cuopt-user-rules/ # Override default (`copy`) → ship symlinks to ../../../skills/<...>/. # No duplicated SKILL.md, plugin tree stays in sync automatically. diff --git a/plugins/nvidia-skills/skills/cuopt-user-rules b/plugins/nvidia-skills/skills/cuopt-user-rules new file mode 120000 index 00000000..3a0eb8bd --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-user-rules @@ -0,0 +1 @@ +../../../skills/cuopt/cuopt-user-rules \ No newline at end of file From 6b9e5dd9d94e63dc44719b4d36e59ea32006edff Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 17:38:30 -0400 Subject: [PATCH 09/11] chore(plugins): switch nvidia-skills back to default copy mode Drop the skill_files: symlink override from plugins.d/nvidia-skills.yml so the plugin inherits skill_files: copy from _defaults.yml. Rebuild materializes the two curated cuopt skills as real directory copies (including the new skill-card.md and skill.oms.sig sidecars now shipping from upstream cuopt) instead of relative symlinks. This is the layout Codex local-marketplace install requires (codex plugin add silently drops symlinks). Trade-off: plugins//skills/ now duplicates SKILL.md content, and copy-mode plugin trees go stale whenever the daily skills sync touches a curated source path. Signed-off-by: Jason Dudash --- plugins.d/nvidia-skills.yml | 7 - .../skills/cuopt-routing-api-python | 1 - .../skills/cuopt-routing-api-python/SKILL.md | 103 ++++++++ .../cuopt-routing-api-python/assets/README.md | 10 + .../assets/pdp_basic/README.md | 7 + .../assets/pdp_basic/model.py | 56 ++++ .../assets/vrp_basic/README.md | 7 + .../assets/vrp_basic/model.py | 31 +++ .../resources/examples.md | 249 ++++++++++++++++++ .../resources/server_examples.md | 204 ++++++++++++++ .../cuopt-routing-api-python/skill-card.md | 38 +++ .../cuopt-routing-api-python/skill.oms.sig | 1 + plugins/nvidia-skills/skills/cuopt-user-rules | 1 - .../skills/cuopt-user-rules/SKILL.md | 222 ++++++++++++++++ .../skills/cuopt-user-rules/skill-card.md | 39 +++ .../skills/cuopt-user-rules/skill.oms.sig | 1 + 16 files changed, 968 insertions(+), 9 deletions(-) delete mode 120000 plugins/nvidia-skills/skills/cuopt-routing-api-python create mode 100644 plugins/nvidia-skills/skills/cuopt-routing-api-python/SKILL.md create mode 100644 plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/pdp_basic/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/pdp_basic/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/vrp_basic/README.md create mode 100644 plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/vrp_basic/model.py create mode 100644 plugins/nvidia-skills/skills/cuopt-routing-api-python/resources/examples.md create mode 100644 plugins/nvidia-skills/skills/cuopt-routing-api-python/resources/server_examples.md create mode 100644 plugins/nvidia-skills/skills/cuopt-routing-api-python/skill-card.md create mode 100644 plugins/nvidia-skills/skills/cuopt-routing-api-python/skill.oms.sig delete mode 120000 plugins/nvidia-skills/skills/cuopt-user-rules create mode 100644 plugins/nvidia-skills/skills/cuopt-user-rules/SKILL.md create mode 100644 plugins/nvidia-skills/skills/cuopt-user-rules/skill-card.md create mode 100644 plugins/nvidia-skills/skills/cuopt-user-rules/skill.oms.sig diff --git a/plugins.d/nvidia-skills.yml b/plugins.d/nvidia-skills.yml index 1b043144..58c91c3e 100644 --- a/plugins.d/nvidia-skills.yml +++ b/plugins.d/nvidia-skills.yml @@ -28,13 +28,6 @@ include_skills: - skills/cuopt/cuopt-routing-api-python/ - skills/cuopt/cuopt-user-rules/ -# Override default (`copy`) → ship symlinks to ../../../skills/<...>/. -# No duplicated SKILL.md, plugin tree stays in sync automatically. -# Works for `claude plugin install` and `npx skills add`. Currently NOT -# compatible with `codex plugin add` (Codex 0.132 silently drops -# symlinks during install) — flip back to `copy` to test Codex. -skill_files: symlink - # Inherits from plugins.d/_defaults.yml: # version, author, homepage, repository, license, # brand_color, capabilities diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python b/plugins/nvidia-skills/skills/cuopt-routing-api-python deleted file mode 120000 index 68ae9452..00000000 --- a/plugins/nvidia-skills/skills/cuopt-routing-api-python +++ /dev/null @@ -1 +0,0 @@ -../../../skills/cuopt/cuopt-routing-api-python \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python/SKILL.md b/plugins/nvidia-skills/skills/cuopt-routing-api-python/SKILL.md new file mode 100644 index 00000000..a8bc2393 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python/SKILL.md @@ -0,0 +1,103 @@ +--- +name: cuopt-routing-api-python +version: "26.08.00" +description: Vehicle routing (VRP, TSP, PDP) with cuOpt — Python API only. Use when the user is building or solving routing in Python. +--- + + +# cuOpt Routing — Python API + +Confirm problem type (TSP, VRP, PDP) and data (locations, orders, fleet, constraints) before coding. + +This skill is **Python only**. Routing has no C API in cuOpt. + +## Minimal VRP Example + +```python +import cudf +from cuopt import routing + +cost_matrix = cudf.DataFrame([...], dtype="float32") +dm = routing.DataModel(n_locations=4, n_fleet=2, n_orders=3) +dm.add_cost_matrix(cost_matrix) +dm.set_order_locations(cudf.Series([1, 2, 3], dtype="int32")) +solution = routing.Solve(dm, routing.SolverSettings()) + +if solution.get_status() == 0: + solution.display_routes() +``` + +## Adding Constraints + +```python +# Time windows +dm.add_transit_time_matrix(transit_time_matrix) +dm.set_order_time_windows(earliest_series, latest_series) + +# Capacities +dm.add_capacity_dimension("weight", demand_series, capacity_series) +dm.set_order_service_times(service_times) +dm.set_vehicle_locations(start_locations, end_locations) +dm.set_vehicle_time_windows(earliest_start, latest_return) + +# Pickup-delivery pairs +dm.set_pickup_delivery_pairs(pickup_indices, delivery_indices) + +# Precedence +dm.add_order_precedence(node_id=2, preceding_nodes=np.array([0, 1])) +``` + +## Solution Checking + +```python +status = solution.get_status() # 0=SUCCESS, 1=FAIL, 2=TIMEOUT, 3=EMPTY +if status == 0: + route_df = solution.get_route() + total_cost = solution.get_total_objective() +else: + print(solution.get_error_message()) + print(solution.get_infeasible_orders().to_list()) +``` + +## Data Types (use explicit dtypes) + +```python +cost_matrix = cost_matrix.astype("float32") +order_locations = cudf.Series([...], dtype="int32") +demand = cudf.Series([...], dtype="int32") +``` + +## Solver Settings + +```python +ss = routing.SolverSettings() +ss.set_time_limit(30) +ss.set_verbose_mode(True) +ss.set_error_logging_mode(True) +``` + +## Common Issues + +| Problem | Fix | +|---------|-----| +| Empty solution | Widen time windows or check travel times | +| Infeasible orders | Increase fleet or capacity | +| Status != 0 with time windows | Add `add_transit_time_matrix()` | +| Wrong cost | Check cost_matrix is symmetric | +| `compute_waypoint_sequence` alters route_df | It replaces the `location` column with waypoint ids in place — pass `route_df.copy()` if you still need cost-matrix indices (e.g. when iterating per truck) | + +## Debugging + +**When status != 0:** `print(solution.get_error_message())` and `print(solution.get_infeasible_orders().to_list())` to see which orders are infeasible. + +**Data types:** Use explicit dtypes (float32, int32) for matrices and series to avoid silent errors. + +## Examples + +- [examples.md](resources/examples.md) — VRP, PDP, multi-depot +- [server_examples.md](resources/server_examples.md) — REST client (curl, Python) +- **Reference models:** This skill's `assets/` — [vrp_basic](assets/vrp_basic/), [pdp_basic](assets/pdp_basic/). See [assets/README.md](assets/README.md). + +## Escalate + +For contribution or build-from-source, see the developer skill. diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/README.md b/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/README.md new file mode 100644 index 00000000..6b7a8091 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/README.md @@ -0,0 +1,10 @@ +# Assets — reference routing models + +Routing reference implementations (Python). Use as reference when building new applications; do not edit in place. + +| Model | Type | Description | +|-------|------|-------------| +| [vrp_basic](vrp_basic/) | VRP | Minimal VRP: 4 locations, 1 vehicle, 3 orders | +| [pdp_basic](pdp_basic/) | PDP | Pickup-delivery pairs, capacity dimension | + +**Run:** From each subdir, `python model.py` (requires cuOpt and cudf). See [resources/examples.md](../resources/examples.md) for more patterns (time windows, multi-depot). diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/pdp_basic/README.md b/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/pdp_basic/README.md new file mode 100644 index 00000000..64e345bb --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/pdp_basic/README.md @@ -0,0 +1,7 @@ +# Pickup-Delivery (PDP) + +2 pickup-delivery pairs (4 orders), 2 vehicles. Pickup must occur before delivery; capacity dimension. + +**Run:** `python model.py` + +**See also:** [resources/examples.md](../../resources/examples.md) for more PDP and VRP patterns. diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/pdp_basic/model.py b/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/pdp_basic/model.py new file mode 100644 index 00000000..d85ec532 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/pdp_basic/model.py @@ -0,0 +1,56 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +PDP: 2 pickup-delivery pairs, 2 vehicles. Pickup before delivery; capacity dimension. +""" + +import cudf +from cuopt import routing + +cost_matrix = cudf.DataFrame( + [ + [0, 10, 20, 30, 40], + [10, 0, 15, 25, 35], + [20, 15, 0, 10, 20], + [30, 25, 10, 0, 15], + [40, 35, 20, 15, 0], + ], + dtype="float32", +) + +transit_time_matrix = cost_matrix.copy(deep=True) +n_fleet = 2 +n_orders = 4 + +order_locations = cudf.Series([1, 2, 3, 4], dtype="int32") +pickup_indices = cudf.Series([0, 2]) +delivery_indices = cudf.Series([1, 3]) +demand = cudf.Series([10, -10, 15, -15], dtype="int32") +vehicle_capacity = cudf.Series([50, 50], dtype="int32") + +dm = routing.DataModel( + n_locations=cost_matrix.shape[0], + n_fleet=n_fleet, + n_orders=n_orders, +) +dm.add_cost_matrix(cost_matrix) +dm.add_transit_time_matrix(transit_time_matrix) +dm.set_order_locations(order_locations) +dm.add_capacity_dimension("load", demand, vehicle_capacity) +dm.set_pickup_delivery_pairs(pickup_indices, delivery_indices) +dm.set_vehicle_locations( + cudf.Series([0, 0], dtype="int32"), + cudf.Series([0, 0], dtype="int32"), +) + +ss = routing.SolverSettings() +ss.set_time_limit(10) +solution = routing.Solve(dm, ss) + +print(f"Status: {solution.get_status()}") +if solution.get_status() == 0: + solution.display_routes() + print(f"Total cost: {solution.get_total_objective()}") +else: + print(solution.get_error_message()) diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/vrp_basic/README.md b/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/vrp_basic/README.md new file mode 100644 index 00000000..cdb28902 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/vrp_basic/README.md @@ -0,0 +1,7 @@ +# Minimal VRP + +4 locations (depot 0 + 3 customers), 1 vehicle, 3 orders. Cost matrix only; no time windows or capacity. + +**Run:** `python model.py` + +**See also:** [resources/examples.md](../../resources/examples.md) for VRP with time windows, capacity, and multi-depot. diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/vrp_basic/model.py b/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/vrp_basic/model.py new file mode 100644 index 00000000..165f6afc --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python/assets/vrp_basic/model.py @@ -0,0 +1,31 @@ +# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +""" +Minimal VRP: 4 locations, 1 vehicle, 3 orders. Cost matrix only. +""" + +import cudf +from cuopt import routing + +cost_matrix = cudf.DataFrame( + [ + [0, 10, 15, 20], + [10, 0, 12, 18], + [15, 12, 0, 10], + [20, 18, 10, 0], + ], + dtype="float32", +) + +dm = routing.DataModel(n_locations=4, n_fleet=1, n_orders=3) +dm.add_cost_matrix(cost_matrix) +dm.set_order_locations(cudf.Series([1, 2, 3], dtype="int32")) + +solution = routing.Solve(dm, routing.SolverSettings()) + +if solution.get_status() == 0: + solution.display_routes() + print(f"Total cost: {solution.get_total_objective()}") +else: + print(f"Status: {solution.get_status()}", solution.get_error_message()) diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python/resources/examples.md b/plugins/nvidia-skills/skills/cuopt-routing-api-python/resources/examples.md new file mode 100644 index 00000000..ee402bb3 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python/resources/examples.md @@ -0,0 +1,249 @@ +# Routing: Python API Examples + +## VRP with Time Windows & Capacities + +```python +""" +Vehicle Routing Problem with: +- 1 depot (location 0) +- 5 customer locations (1-5) +- 2 vehicles with capacity 100 each +- Time windows for each location +- Demand at each customer +""" +import cudf +from cuopt import routing + +# Cost/distance matrix (6x6: depot + 5 customers) +cost_matrix = cudf.DataFrame([ + [0, 10, 15, 20, 25, 30], # From depot + [10, 0, 12, 18, 22, 28], # From customer 1 + [15, 12, 0, 10, 15, 20], # From customer 2 + [20, 18, 10, 0, 8, 15], # From customer 3 + [25, 22, 15, 8, 0, 10], # From customer 4 + [30, 28, 20, 15, 10, 0], # From customer 5 +], dtype="float32") + +# Also use as transit time matrix (same values for simplicity) +transit_time_matrix = cost_matrix.copy(deep=True) + +# Order data (customers 1-5) +order_locations = cudf.Series([1, 2, 3, 4, 5], dtype="int32") # Location indices for orders + +# Demand at each customer (single capacity dimension) +demand = cudf.Series([20, 30, 25, 15, 35], dtype="int32") + +# Vehicle capacities (must match demand dimensions) +vehicle_capacity = cudf.Series([100, 100], dtype="int32") + +# Time windows for orders [earliest, latest] +order_earliest = cudf.Series([0, 10, 20, 0, 30], dtype="int32") +order_latest = cudf.Series([50, 60, 70, 80, 90], dtype="int32") + +# Service time at each customer +service_times = cudf.Series([5, 5, 5, 5, 5], dtype="int32") + +# Fleet configuration +n_fleet = 2 + +# Vehicle start/end locations (both start and return to depot) +vehicle_start = cudf.Series([0, 0], dtype="int32") +vehicle_end = cudf.Series([0, 0], dtype="int32") + +# Vehicle time windows (operating hours) +vehicle_earliest = cudf.Series([0, 0], dtype="int32") +vehicle_latest = cudf.Series([200, 200], dtype="int32") + +# Build the data model +dm = routing.DataModel( + n_locations=cost_matrix.shape[0], + n_fleet=n_fleet, + n_orders=len(order_locations) +) + +# Add matrices +dm.add_cost_matrix(cost_matrix) +dm.add_transit_time_matrix(transit_time_matrix) + +# Add order data +dm.set_order_locations(order_locations) +dm.set_order_time_windows(order_earliest, order_latest) +dm.set_order_service_times(service_times) + +# Add capacity dimension (name, demand_per_order, capacity_per_vehicle) +dm.add_capacity_dimension("weight", demand, vehicle_capacity) + +# Add fleet data +dm.set_vehicle_locations(vehicle_start, vehicle_end) +dm.set_vehicle_time_windows(vehicle_earliest, vehicle_latest) + +# Configure solver +ss = routing.SolverSettings() +ss.set_time_limit(10) # seconds + +# Solve +solution = routing.Solve(dm, ss) + +# Check solution status +print(f"Status: {solution.get_status()}") + +# Display routes +if solution.get_status() == 0: # Success + print("\n--- Solution Found ---") + solution.display_routes() + + # Get detailed route data + route_df = solution.get_route() + print("\nDetailed route data:") + print(route_df) + + # Get objective value (total cost) + print(f"\nTotal cost: {solution.get_total_objective()}") +else: + print("No feasible solution found (status != 0).") +``` + +## Pickup and Delivery Problem (PDP) + +```python +""" +Pickup and Delivery Problem: +- Items must be picked up from one location and delivered to another +- Same vehicle must do both pickup and delivery +- Pickup must occur before delivery +""" +import cudf +from cuopt import routing + +# Cost matrix (depot + 4 locations) +cost_matrix = cudf.DataFrame([ + [0, 10, 20, 30, 40], + [10, 0, 15, 25, 35], + [20, 15, 0, 10, 20], + [30, 25, 10, 0, 15], + [40, 35, 20, 15, 0], +], dtype="float32") + +transit_time_matrix = cost_matrix.copy(deep=True) + +n_fleet = 2 +n_orders = 4 # 2 pickup-delivery pairs = 4 orders + +# Orders: pickup at loc 1 -> deliver at loc 2, pickup at loc 3 -> deliver at loc 4 +order_locations = cudf.Series([1, 2, 3, 4], dtype="int32") + +# Pickup and delivery pairs (indices into order array) +# Order 0 (pickup) pairs with Order 1 (delivery) +# Order 2 (pickup) pairs with Order 3 (delivery) +pickup_indices = cudf.Series([0, 2]) +delivery_indices = cudf.Series([1, 3]) + +# Demand: positive for pickup, negative for delivery (must sum to 0 per pair) +demand = cudf.Series([10, -10, 15, -15], dtype="int32") +vehicle_capacity = cudf.Series([50, 50], dtype="int32") + +# Build model +dm = routing.DataModel( + n_locations=cost_matrix.shape[0], + n_fleet=n_fleet, + n_orders=n_orders +) + +dm.add_cost_matrix(cost_matrix) +dm.add_transit_time_matrix(transit_time_matrix) +dm.set_order_locations(order_locations) + +# Add capacity dimension +dm.add_capacity_dimension("load", demand, vehicle_capacity) + +# Set pickup and delivery constraints +dm.set_pickup_delivery_pairs(pickup_indices, delivery_indices) + +# Fleet setup +dm.set_vehicle_locations( + cudf.Series([0, 0]), # Start at depot + cudf.Series([0, 0]) # Return to depot +) + +# Solve +ss = routing.SolverSettings() +ss.set_time_limit(10) +solution = routing.Solve(dm, ss) + +print(f"Status: {solution.get_status()}") +if solution.get_status() == 0: + solution.display_routes() +``` + +## Minimal VRP (Quick Start) + +```python +import cudf +from cuopt import routing + +# Minimal 4-location problem +cost_matrix = cudf.DataFrame([ + [0, 10, 15, 20], + [10, 0, 12, 18], + [15, 12, 0, 10], + [20, 18, 10, 0], +], dtype="float32") + +dm = routing.DataModel(n_locations=4, n_fleet=1, n_orders=3) +dm.add_cost_matrix(cost_matrix) +dm.set_order_locations(cudf.Series([1, 2, 3], dtype="int32")) + +solution = routing.Solve(dm, routing.SolverSettings()) + +if solution.get_status() == 0: + solution.display_routes() +``` + +## Multi-Depot VRP + +```python +import cudf +from cuopt import routing + +# 6 locations: 2 depots (0, 1) + 4 customers (2, 3, 4, 5) +cost_matrix = cudf.DataFrame([ + [0, 5, 10, 15, 20, 25], + [5, 0, 12, 8, 18, 22], + [10, 12, 0, 6, 14, 16], + [15, 8, 6, 0, 10, 12], + [20, 18, 14, 10, 0, 8], + [25, 22, 16, 12, 8, 0], +], dtype="float32") + +n_fleet = 2 + +dm = routing.DataModel(n_locations=6, n_fleet=n_fleet, n_orders=4) +dm.add_cost_matrix(cost_matrix) +dm.set_order_locations(cudf.Series([2, 3, 4, 5], dtype="int32")) + +# Vehicle 0 starts/ends at depot 0, Vehicle 1 at depot 1 +dm.set_vehicle_locations( + cudf.Series([0, 1]), # start locations + cudf.Series([0, 1]) # end locations +) + +solution = routing.Solve(dm, routing.SolverSettings()) +if solution.get_status() == 0: + solution.display_routes() +``` + +--- + +## Additional References (tested in CI) + +For more complete examples, read these files: + +| Example | File | Description | +|---------|------|-------------| +| Basic Routing | `docs/cuopt/source/cuopt-server/examples/routing/examples/basic_routing_example.py` | Server-based routing | +| Initial Solution | `docs/cuopt/source/cuopt-server/examples/routing/examples/initial_solution_example.py` | Warm starting | +| Smoke Test | `docs/cuopt/source/cuopt-python/routing/examples/smoke_test_example.sh` | Quick validation | + +These examples are tested by CI and represent canonical usage. + +**Note:** The Python routing API documentation is in `python/cuopt/cuopt/routing/vehicle_routing.py` (docstrings). diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python/resources/server_examples.md b/plugins/nvidia-skills/skills/cuopt-routing-api-python/resources/server_examples.md new file mode 100644 index 00000000..06d03dbe --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python/resources/server_examples.md @@ -0,0 +1,204 @@ +# Routing: REST Server Examples + +## Start the Server + +```bash +# Start server +python -m cuopt_server.cuopt_service --ip 0.0.0.0 --port 8000 & + +# Wait and verify +sleep 5 +curl -s http://localhost:8000/cuopt/health +``` + +## Basic VRP (curl) + +```bash +REQID=$(curl -s -X POST "http://localhost:8000/cuopt/request" \ + -H "Content-Type: application/json" \ + -H "CLIENT-VERSION: custom" \ + -d '{ + "cost_matrix_data": { + "data": {"0": [[0,10,15,20],[10,0,12,18],[15,12,0,10],[20,18,10,0]]} + }, + "travel_time_matrix_data": { + "data": {"0": [[0,10,15,20],[10,0,12,18],[15,12,0,10],[20,18,10,0]]} + }, + "task_data": { + "task_locations": [1, 2, 3], + "demand": [[10, 15, 20]], + "task_time_windows": [[0, 100], [10, 80], [20, 90]], + "service_times": [5, 5, 5] + }, + "fleet_data": { + "vehicle_locations": [[0, 0], [0, 0]], + "capacities": [[50, 50]], + "vehicle_time_windows": [[0, 200], [0, 200]] + }, + "solver_config": { + "time_limit": 5 + } + }' | jq -r '.reqId') + +echo "Request ID: $REQID" + +# Poll for solution +sleep 2 +curl -s "http://localhost:8000/cuopt/solution/$REQID" \ + -H "Content-Type: application/json" \ + -H "CLIENT-VERSION: custom" | jq . +``` + +## VRP with Time Windows (Python requests) + +```python +import requests +import time + +SERVER = "http://localhost:8000" +HEADERS = {"Content-Type": "application/json", "CLIENT-VERSION": "custom"} + +payload = { + "cost_matrix_data": { + "data": { + "0": [ + [0, 10, 15, 20, 25], + [10, 0, 12, 18, 22], + [15, 12, 0, 10, 15], + [20, 18, 10, 0, 8], + [25, 22, 15, 8, 0] + ] + } + }, + "travel_time_matrix_data": { + "data": { + "0": [ + [0, 10, 15, 20, 25], + [10, 0, 12, 18, 22], + [15, 12, 0, 10, 15], + [20, 18, 10, 0, 8], + [25, 22, 15, 8, 0] + ] + } + }, + "task_data": { + "task_locations": [1, 2, 3, 4], + "demand": [[20, 30, 25, 15]], + "task_time_windows": [[0, 50], [10, 60], [20, 70], [0, 80]], + "service_times": [5, 5, 5, 5] + }, + "fleet_data": { + "vehicle_locations": [[0, 0], [0, 0]], + "capacities": [[100, 100]], + "vehicle_time_windows": [[0, 200], [0, 200]] + }, + "solver_config": { + "time_limit": 10 + } +} + +# Submit request +response = requests.post(f"{SERVER}/cuopt/request", json=payload, headers=HEADERS) +response.raise_for_status() +req_id = response.json()["reqId"] +print(f"Request submitted: {req_id}") + +# Poll for solution +for attempt in range(30): + response = requests.get(f"{SERVER}/cuopt/solution/{req_id}", headers=HEADERS) + result = response.json() + + if "response" in result: + solver_response = result["response"].get("solver_response", {}) + print(f"\nSolution found!") + print(f"Status: {solver_response.get('status', 'N/A')}") + print(f"Cost: {solver_response.get('solution_cost', 'N/A')}") + + if "vehicle_data" in solver_response: + for vid, vdata in solver_response["vehicle_data"].items(): + route = vdata.get("route", []) + print(f"Vehicle {vid}: {' -> '.join(map(str, route))}") + break + else: + print(f"Waiting... (attempt {attempt + 1})") + time.sleep(1) +``` + +## Pickup and Delivery (curl) + +```bash +REQID=$(curl -s -X POST "http://localhost:8000/cuopt/request" \ + -H "Content-Type: application/json" \ + -H "CLIENT-VERSION: custom" \ + -d '{ + "cost_matrix_data": { + "data": {"0": [[0,10,20,30,40],[10,0,15,25,35],[20,15,0,10,20],[30,25,10,0,15],[40,35,20,15,0]]} + }, + "travel_time_matrix_data": { + "data": {"0": [[0,10,20,30,40],[10,0,15,25,35],[20,15,0,10,20],[30,25,10,0,15],[40,35,20,15,0]]} + }, + "task_data": { + "task_locations": [1, 2, 3, 4], + "demand": [[10, -10, 15, -15]], + "pickup_and_delivery_pairs": [[0, 1], [2, 3]] + }, + "fleet_data": { + "vehicle_locations": [[0, 0]], + "capacities": [[50]] + }, + "solver_config": { + "time_limit": 10 + } + }' | jq -r '.reqId') + +echo "Request ID: $REQID" + +# Poll for solution +sleep 2 +curl -s "http://localhost:8000/cuopt/solution/$REQID" \ + -H "Content-Type: application/json" \ + -H "CLIENT-VERSION: custom" | jq . +``` + +## Terminology Reference + +| Python API | REST Server API | +|------------|-----------------| +| `order_locations` | `task_locations` | +| `set_order_time_windows()` | `task_time_windows` | +| `set_order_service_times()` | `service_times` | +| `add_transit_time_matrix()` | `travel_time_matrix_data` | +| `set_pickup_delivery_pairs()` | `pickup_and_delivery_pairs` | + +## Common Payload Mistakes + +```json +// ❌ WRONG field name +"transit_time_matrix_data": {...} + +// ✅ CORRECT +"travel_time_matrix_data": {...} +``` + +```json +// ❌ WRONG capacity format (per vehicle) +"capacities": [[50], [50]] + +// ✅ CORRECT (per dimension across vehicles) +"capacities": [[50, 50]] +``` + +--- + +## Additional References (tested in CI) + +For more complete examples, read these files: + +| Example | File | Description | +|---------|------|-------------| +| Basic Routing (Python) | `docs/cuopt/source/cuopt-server/examples/routing/examples/basic_routing_example.py` | VRP via REST | +| Basic Routing (curl) | `docs/cuopt/source/cuopt-server/examples/routing/examples/basic_routing_example.sh` | Shell script | +| Initial Solution | `docs/cuopt/source/cuopt-server/examples/routing/examples/initial_solution_example.py` | Warm starting | +| Initial Solution (curl) | `docs/cuopt/source/cuopt-server/examples/routing/examples/initial_solution_example.sh` | Warm start shell | + +These examples are tested by CI (`ci/test_doc_examples.sh`) and represent canonical usage. diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python/skill-card.md b/plugins/nvidia-skills/skills/cuopt-routing-api-python/skill-card.md new file mode 100644 index 00000000..69ece75f --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python/skill-card.md @@ -0,0 +1,38 @@ +## Description:
+Vehicle routing (VRP, TSP, PDP) with cuOpt — Python API only. Use when the user is building or solving routing in Python.
+ +This skill is ready for commercial/non-commercial use.
+ +## Owner: NVIDIA
+ +### License/Terms of Use:
+Apache 2.0
+## Use Case:
+Developers and engineers building or solving vehicle routing problems (VRP, TSP, PDP) using the NVIDIA cuOpt Python API for GPU-accelerated optimization.
+ +### Deployment Geography for Use:
+Global
+ +## Known Risks and Mitigations:
+Risk: Review before execution as proposals could introduce incorrect or misleading guidance into skills.
+Mitigation: Review and scan skill before deployment.
+ +## Reference(s):
+- [cuOpt User Guide](https://docs.nvidia.com/cuopt/user-guide/latest/introduction.html)
+- [cuOpt Examples Repository](https://github.com/NVIDIA/cuopt-examples)
+ + +## Skill Output:
+**Output Type(s):** [Code, API Calls, Configuration instructions]
+**Output Format:** [Markdown with inline Python code blocks]
+**Output Parameters:** [1D]
+**Other Properties Related to Output:** [None]
+ +## Skill Version(s):
+26.06.00 (source: frontmatter)
+ +## Ethical Considerations:
+NVIDIA believes Trustworthy AI is a shared responsibility and we have established policies and practices to enable development for a wide array of AI applications. When downloaded or used in accordance with our terms of service, developers should work with their internal team to ensure this skill meets requirements for the relevant industry and use case and addresses unforeseen product misuse.
+ +(For Release on NVIDIA Platforms Only)
+Please report quality, risk, security vulnerabilities or NVIDIA AI Concerns [here](https://app.intigriti.com/programs/nvidia/nvidiavdp/detail).
diff --git a/plugins/nvidia-skills/skills/cuopt-routing-api-python/skill.oms.sig b/plugins/nvidia-skills/skills/cuopt-routing-api-python/skill.oms.sig new file mode 100644 index 00000000..ef91a123 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-routing-api-python/skill.oms.sig @@ -0,0 +1 @@ +{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json","verificationMaterial":{"x509CertificateChain":{"certificates":[{"rawBytes":"MIICgzCCAgmgAwIBAgIUKIyS7SxNteQIiWzK1dWj85E6520wCgYIKoZIzj0EAwMwVTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjEpMCcGA1UEAwwgTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBJQ0EgMDEwHhcNMjYwNDAxMDAwMDAwWhcNMjgwNDIyMTUzMzA5WjBUMQswCQYDVQQGEwJVUzEbMBkGA1UECgwSTlZJRElBIENvcnBvcmF0aW9uMSgwJgYDVQQDDB9OVklESUEgQWdlbnQgU2tpbGxzIFNpZ25pbmcgMDAxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEYoRM9bQl/dGlwSRNi6bTpIJUXH8Nv9GciP6LSflJYYMLCc296kpyuTSsk5ddbAWiDcFX3C/ydX3jwc+qCLYP6uHy9XphyLjOQ27Yb2J6rBLVtRBS1mgGco/Gr7fL6ODco4GaMIGXMB0GA1UdDgQWBBRQ/5ZW3nJ6lmo9SVk7I15o7UGmpTAfBgNVHSMEGDAWgBRPGpILxMBBleJSsBGjrMKsby1CgjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3NwLm5kaXMubnZpZGlhLmNvbTAKBggqhkjOPQQDAwNoADBlAjAUygu/GiOCIXrgGr4SmLgeEVDcEitfFUv7ALbvLVGVyMysB3mxmO/uInZfXzWcJZsCMQDxuoxj4ZmO30jhkPIcCxGFCOvnUsnfU3TfGcouYm4M6iRpbKvtVnHPiy4bi6pcKf0="},{"rawBytes":"MIICiDCCAg6gAwIBAgIUZsIuSv9NkpJCNqtYEfCouVv5BzowCgYIKoZIzj0EAwMwUTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBDQTAgFw0yNjA0MDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowVTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjEpMCcGA1UEAwwgTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBJQ0EgMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASI72cR3ctKGg4VWnB3bNja6g1Z2PnOmFEopkPof+QeIcPk9rT+g9MjJnq51EQXL93a7C2GJ9J985G4o2V85VD7wJ1RaXhluHW2rf3y8bQGeAYaKMr5s/hUgn+M3/9WlWejgaAwgZ0wHQYDVR0OBBYEFE8akgvEwEGV4lKwEaOswqxvLUKCMB8GA1UdIwQYMBaAFItnoAjjfuCEUvzyvWyI2vOGvwPjMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AubmRpcy5udmlkaWEuY29tMAoGCCqGSM49BAMDA2gAMGUCMQCeIMMfAbyzPDacw2MxG+Yt1cikrJX/DVxiGfXuHmkkXn6VgSzE79+lkqDErpVO2gYCMCNEColOyvUvkzZGUEI1hQ3PfMgi3FIo9tHoBKMw4/wGBLFpu/0ubtmbBXM6/UMOEw=="},{"rawBytes":"MIICRTCCAcygAwIBAgIUeJdY3rV86EdvFmG7L8LJBsyQFYkwCgYIKoZIzj0EAwMwUTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBDQTAgFw0yNjA0MDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowUTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABAYpiXCDjJ9NT2eSDhyHJVSw1Tbze18cGG2F/578oWvHxg23eQAhNRYdq88i1iOshZSO6C29doKui5Xpmo/7Ctw9Sx4PP2RzOmIuOLCuTdNtKcTRwi4GEsd5BAFvWj42M6NjMGEwHQYDVR0OBBYEFItnoAjjfuCEUvzyvWyI2vOGvwPjMB8GA1UdIwQYMBaAFItnoAjjfuCEUvzyvWyI2vOGvwPjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMCwtAjWLaNwgGWNCgdyNoTyvNhqWRECRJV2r3+7w8g0PL6NHLOsbkgE09BH95h8XlgIwTaQmbbUh2ChAJ5TA1wRiVDnCcvbzHlZl2jM2FcwQQZlk19LOAbyGMRixbu2Ww/rj"}]},"tlogEntries":[]},"dsseEnvelope":{"payload":"ewogICJfdHlwZSI6ICJodHRwczovL2luLXRvdG8uaW8vU3RhdGVtZW50L3YxIiwKICAic3ViamVjdCI6IFsKICAgIHsKICAgICAgIm5hbWUiOiAiY3VvcHQtcm91dGluZy1hcGktcHl0aG9uIiwKICAgICAgImRpZ2VzdCI6IHsKICAgICAgICAic2hhMjU2IjogIjIzMzI3ODUwMDkzZTVlZDQwZmYxYmUyZDE5ODEyNTdkNTcyOTQ4YjEzMTRlYTRkZDQyYmY4M2NlZjRjZGU0YTAiCiAgICAgIH0KICAgIH0KICBdLAogICJwcmVkaWNhdGVUeXBlIjogImh0dHBzOi8vbW9kZWxfc2lnbmluZy9zaWduYXR1cmUvdjEuMCIsCiAgInByZWRpY2F0ZSI6IHsKICAgICJyZXNvdXJjZXMiOiBbCiAgICAgIHsKICAgICAgICAibmFtZSI6ICJTS0lMTC5tZCIsCiAgICAgICAgImRpZ2VzdCI6ICI3Yzc0ZTM5NjNlOWQ0OWU0NGVkZTJkMjU1YWZmYTNmYjMzZmQzMTU4YWE4ZmRmOGE4Zjc1Mjc5YjlmMzdmMjIxIiwKICAgICAgICAiYWxnb3JpdGhtIjogInNoYTI1NiIKICAgICAgfSwKICAgICAgewogICAgICAgICJuYW1lIjogImFzc2V0cy9SRUFETUUubWQiLAogICAgICAgICJkaWdlc3QiOiAiMGQ3N2Y4YTZiNzkwYTk2NzRlNDQ3NThlYTMwNDU3NTNmNGExZGM0MTdlMjAxNDc5ZGVkZWUwMjZlM2Y4MzJlOSIsCiAgICAgICAgImFsZ29yaXRobSI6ICJzaGEyNTYiCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAibmFtZSI6ICJhc3NldHMvcGRwX2Jhc2ljL1JFQURNRS5tZCIsCiAgICAgICAgImRpZ2VzdCI6ICI3Y2YzNzk3ZDA5OGE1NTM0YTBiMmMxMzA5ZjYzNWQ2ZThlYTdkZjYyYjllNTk0NjliNmU1NjQyOTIyZDVjYjQ0IiwKICAgICAgICAiYWxnb3JpdGhtIjogInNoYTI1NiIKICAgICAgfSwKICAgICAgewogICAgICAgICJuYW1lIjogImFzc2V0cy9wZHBfYmFzaWMvbW9kZWwucHkiLAogICAgICAgICJkaWdlc3QiOiAiMTQ0ZGExZGY1ZGUyOGQ3ODVhOWI0NjdiM2QxNDQxN2U3MTZmNTMyYWM5Yjk4OTA0NmVhZjdlNGY1Mjk5YTVmZCIsCiAgICAgICAgImFsZ29yaXRobSI6ICJzaGEyNTYiCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAibmFtZSI6ICJhc3NldHMvdnJwX2Jhc2ljL1JFQURNRS5tZCIsCiAgICAgICAgImRpZ2VzdCI6ICI0YTIyM2UxZWI0ZDAwYjJlODhiODRhN2NhMzA0NjE2NjBlNDgwMzE4ZThlYzRiYTUwNjAyMzBjZDk4MmU1MzRmIiwKICAgICAgICAiYWxnb3JpdGhtIjogInNoYTI1NiIKICAgICAgfSwKICAgICAgewogICAgICAgICJuYW1lIjogImFzc2V0cy92cnBfYmFzaWMvbW9kZWwucHkiLAogICAgICAgICJkaWdlc3QiOiAiNTI0NWI3NzQ2NWEyNmI2OGFlZmJhYTMyNDliNTFlZjBkYTQ1MDVmNGUxOTc0Y2Y2ZDBmNDRiMWM3OGZjODA3MCIsCiAgICAgICAgImFsZ29yaXRobSI6ICJzaGEyNTYiCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAibmFtZSI6ICJyZXNvdXJjZXMvZXhhbXBsZXMubWQiLAogICAgICAgICJkaWdlc3QiOiAiNWViMzU3MzU1NTlkOTM1YzIxZTIwYTQ5NTkxZDU0YzliNmZhOTI0NzIxN2FhNDc3NmE1Zjg5ODNjYmQyN2Y4MSIsCiAgICAgICAgImFsZ29yaXRobSI6ICJzaGEyNTYiCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAibmFtZSI6ICJyZXNvdXJjZXMvc2VydmVyX2V4YW1wbGVzLm1kIiwKICAgICAgICAiZGlnZXN0IjogIjUwOGJmNGFlOGNiNWJjN2UyNDliMzc3MjYwZjE0MjFiNzBkOWQzNDViYjVhNmQxNmM2ZmEwYjU2ZTI1NjgyNWIiLAogICAgICAgICJhbGdvcml0aG0iOiAic2hhMjU2IgogICAgICB9LAogICAgICB7CiAgICAgICAgIm5hbWUiOiAic2tpbGwtY2FyZC5tZCIsCiAgICAgICAgImRpZ2VzdCI6ICI2NDcwYzRjOWE2NjJjNTQ2NjgwNmRmOGFmM2U3NGQ3NGVlODBlY2VlN2U4MzYyZjhiY2UzMjQ1OTAwODJhNzlkIiwKICAgICAgICAiYWxnb3JpdGhtIjogInNoYTI1NiIKICAgICAgfQogICAgXSwKICAgICJzZXJpYWxpemF0aW9uIjogewogICAgICAiaGFzaF90eXBlIjogInNoYTI1NiIsCiAgICAgICJpZ25vcmVfcGF0aHMiOiBbCiAgICAgICAgIi5naXQiLAogICAgICAgICIuZ2l0aWdub3JlIiwKICAgICAgICAiLmdpdGF0dHJpYnV0ZXMiLAogICAgICAgICIuZ2l0aHViIgogICAgICBdLAogICAgICAibWV0aG9kIjogImZpbGVzIiwKICAgICAgImFsbG93X3N5bWxpbmtzIjogZmFsc2UKICAgIH0KICB9Cn0=","payloadType":"application/vnd.in-toto+json","signatures":[{"sig":"MGUCMQCcGZqaSXabbjPR8wp86n7/8am2Wf1/VojZaXO9mP2ZiizEDj3f2BC38yJq4Ft1Iu8CMAORDnqPrWpHhermkTL/X7I8cJtd3F8k8G9fsxxrS+Ucn6JKiEFMMHU68esX8gZSrg==","keyid":""}]}} \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/cuopt-user-rules b/plugins/nvidia-skills/skills/cuopt-user-rules deleted file mode 120000 index 3a0eb8bd..00000000 --- a/plugins/nvidia-skills/skills/cuopt-user-rules +++ /dev/null @@ -1 +0,0 @@ -../../../skills/cuopt/cuopt-user-rules \ No newline at end of file diff --git a/plugins/nvidia-skills/skills/cuopt-user-rules/SKILL.md b/plugins/nvidia-skills/skills/cuopt-user-rules/SKILL.md new file mode 100644 index 00000000..47ce33a4 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-user-rules/SKILL.md @@ -0,0 +1,222 @@ +--- +name: cuopt-user-rules +version: "26.08.00" +description: Base rules for end users calling NVIDIA cuOpt (routing/LP/MILP/QP/install/server). Not for cuOpt internals — use cuopt-developer for those. +--- + + +# cuOpt User Rules + +**Read this when helping someone *use* cuOpt** (calling the SDK, installing, deploying the server). For modifying cuOpt itself, switch to `cuopt-developer`. + +--- + +## Ask Before Assuming + +**Always clarify ambiguous requirements before implementing:** + +- What **language/interface**? +- What problem type? +- What constraints matter? +- What output format? + +**Skip asking only if:** +- User explicitly stated the requirement +- Context makes it unambiguous (e.g., user shows Python code) + +--- + +## Handle Incomplete Questions + +**If a question seems partial or incomplete, ask follow-up questions:** + +- "Could you tell me more about [missing detail]?" +- "What specifically would you like to achieve with this?" +- "Are there any constraints or requirements I should know about?" + +**Common missing information to probe for:** +- Problem size (number of vehicles, locations, variables, constraints) +- Specific constraints (time windows, capacities, precedence) +- Performance requirements (time limits, solution quality) +- Integration context (existing codebase, deployment environment) + +**Don't guess — ask.** A brief clarifying question saves time vs. solving the wrong problem. + +--- + +## Clarify Data Requirements + +**Before generating examples, ask about data:** + +1. **Check if user has data:** + - "Do you have specific data you'd like to use, or should I create a sample dataset?" + - "Can you share the format of your input data?" + +2. **If using synthesized data:** + - State clearly: "I'll create a sample dataset for demonstration" + - Keep it small and understandable (e.g., 5-10 locations, 2-3 vehicles) + - Make values realistic and meaningful + +3. **Always document what you used:** + ``` + "For this example I'm using: + - [X] locations/variables/constraints + - [Key assumptions: e.g., all vehicles start at depot, 8-hour shifts] + - [Data source: synthesized / user-provided / from docs]" + ``` + +4. **State assumptions explicitly:** + - "I'm assuming [X] — let me know if this differs from your scenario" + - List any default values or simplifications made + +--- + +## MUST Verify Understanding + +**Before writing substantial code, you MUST confirm your understanding:** + +``` +"Let me confirm I understand: +- Problem: [restate in your words] +- Constraints: [list them] +- Objective: [minimize/maximize what] +- Interface: [Python/REST/C/CLI] +Is this correct?" +``` + +--- + +## Follow Requirements Exactly + +- Use the **exact** variable names, formats, and structures the user specifies +- Don't add features the user didn't ask for +- Don't change the problem formulation unless asked +- If user provides partial code, extend it—don't rewrite from scratch + +--- + +## Check Results + +After providing a solution, guide the user to verify: + +- **Status check**: Is it `Optimal` / `FeasibleFound` / `SUCCESS`? +- **Constraint satisfaction**: Are all constraints met? +- **Objective value**: Is it reasonable for the problem? + +**Always end with a Result summary** that includes at least: +- Solver status (e.g. Optimal, FeasibleFound, SUCCESS). +- **Objective value with highlight** — easy to spot (bold or code block). Example: **Objective value (min total cost):** <value> or `Objective value: `. +- Briefly what the objective represents (e.g. total cost, total profit). + +Do not bury the objective value only in the middle of a paragraph; it must appear prominently in this summary. Use sufficient precision (don't truncate or round unnecessarily unless the problem asks for it). + +**Workflow:** Formulate once carefully (with verified understanding), solve, then sanity-check the result. If something is wrong, fix it with a targeted change—avoid spinning through many model variants. Decide, implement, verify, then move on. + +Provide diagnostic code snippets when helpful. + +### Post-correction check (mandatory) +If the result required a correction, retry, or workaround to reach this point, you MUST evaluate the skill-evolution workflow (`skills/skill-evolution/SKILL.md`) before moving on. Do not skip this step. + +--- + +## Check Environment First + +**Before writing code or suggesting installation, verify the user's setup:** + +1. **Ask how they access cuOpt:** + - "Do you have cuOpt installed? If so, which interface?" + - "What environment are you using? (local GPU, cloud, Docker, server, etc.)" + +2. **Different packages by language/interface:** + + | Language / Interface | Package | Check | + |----------------------|---------|-------| + | **Python** | `cuopt` (pip/conda) — also pulls in `libcuopt` | `import cuopt` | + | **C** | `libcuopt` (pip/conda) — already present if `cuopt` is installed | `find libcuopt.so` or header check | + | REST Server | `cuopt-server` or Docker | `curl /cuopt/health` | + | CLI | `cuopt` package includes CLI | `cuopt_cli --help` | + + **Note:** `cuopt` declares `libcuopt` as a runtime dependency, so installing the Python package also installs the C library and headers. Installing `libcuopt` on its own does **not** install the Python API. + +3. **If not installed, ask how they want to access:** + - "Would you like help installing cuOpt, or do you have access another way?" + - Options: pip, conda, Docker, cloud instance, existing remote server + +4. **Never assume installation is needed** — the user may: + - Already have it installed + - Be connecting to a remote server + - Prefer a specific installation method + - Only need the C library (not Python) + +5. **Ask before running any verification commands:** + ```python + # Python API check - ask first + import cuopt + print(cuopt.__version__) + ``` + ```bash + # C API check - ask first + find ${CONDA_PREFIX} -name "libcuopt.so" + ``` + ```bash + # Server check - ask first + curl http://localhost:8000/cuopt/health + ``` + +--- + +## Ask Before Running + +**Do not execute commands or code without explicit permission:** + +| Action | Rule | +|--------|------| +| Shell commands | Show command, explain what it does, ask "Should I run this?" | +| Package installs | **Never** run installs yourself — give the exact command, user runs it (see below). | +| Examples/scripts | Show the code first, ask "Would you like me to run this?" | +| File writes | Explain what will change, ask before writing | + +**Exceptions (okay without asking):** +- Read-only commands the user explicitly requested +- Commands the user just provided and asked you to run + +--- + +## No Privileged Operations + +**Never do these without explicit user request AND confirmation:** + +- Use `sudo` or run as root +- Modify system files or configurations +- Add package repositories or keys +- Change firewall, network, or driver settings +- Write files outside the workspace + +--- + +## Never Install Packages Automatically + +> **🔒 MANDATORY — You MUST NOT install, upgrade, or modify packages.** Provide the exact command; the user runs it. No exceptions. + +| Forbidden | What to do instead | +|-----------|--------------------| +| `pip install ...`, `conda install ...`, `apt install ...`, any package manager | Give the exact command and ask the user to run it. Say why the package is needed. | + +**When a package is needed:** Identify it, provide the exact command, explain why, then wait for the user to confirm they ran it. Even if the user says "just install it", give the command and require them to execute it themselves. + +--- + +## Resources + +### Documentation +- [cuOpt User Guide](https://docs.nvidia.com/cuopt/user-guide/latest/introduction.html) +- [API Reference](https://docs.nvidia.com/cuopt/user-guide/latest/api.html) + +### Examples +- [cuopt-examples repo](https://github.com/NVIDIA/cuopt-examples) +- [Google Colab notebooks](https://colab.research.google.com/github/nvidia/cuopt-examples/) + +### Support +- [File a Bug](https://github.com/NVIDIA/cuopt/issues/new?template=bug_report.md) +- [Ask a Question](https://github.com/NVIDIA/cuopt/issues/new?template=submit-question.md) +- [All Issues](https://github.com/NVIDIA/cuopt/issues) diff --git a/plugins/nvidia-skills/skills/cuopt-user-rules/skill-card.md b/plugins/nvidia-skills/skills/cuopt-user-rules/skill-card.md new file mode 100644 index 00000000..1a3212da --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-user-rules/skill-card.md @@ -0,0 +1,39 @@ +## Description:
+Base rules for end users calling NVIDIA cuOpt (routing/LP/MILP/QP/install/server). Not for cuOpt internals — use cuopt-developer for those.
+ +This skill is ready for commercial/non-commercial use.
+ +## Owner: NVIDIA
+ +### License/Terms of Use:
+Apache 2.0
+## Use Case:
+Developers and engineers who interact with cuOpt for optimization tasks use this skill to receive consistent, safe, and methodical guidance on installation, API usage, problem formulation, and result verification across all cuOpt interfaces.
+ +### Deployment Geography for Use:
+Global
+ +## Known Risks and Mitigations:
+Risk: Review before execution as proposals could introduce incorrect or misleading guidance into skills.
+Mitigation: Review and scan skill before deployment.
+ +## Reference(s):
+- [cuOpt User Guide](https://docs.nvidia.com/cuopt/user-guide/latest/introduction.html)
+- [cuOpt API Reference](https://docs.nvidia.com/cuopt/user-guide/latest/api.html)
+- [cuOpt Examples Repository](https://github.com/NVIDIA/cuopt-examples)
+ + +## Skill Output:
+**Output Type(s):** [Configuration instructions, Code, Shell commands]
+**Output Format:** [Markdown with inline code blocks]
+**Output Parameters:** [1D]
+**Other Properties Related to Output:** [None]
+ +## Skill Version(s):
+26.06.00 (source: frontmatter)
+ +## Ethical Considerations:
+NVIDIA believes Trustworthy AI is a shared responsibility and we have established policies and practices to enable development for a wide array of AI applications. When downloaded or used in accordance with our terms of service, developers should work with their internal team to ensure this skill meets requirements for the relevant industry and use case and addresses unforeseen product misuse.
+ +(For Release on NVIDIA Platforms Only)
+Please report quality, risk, security vulnerabilities or NVIDIA AI Concerns [here](https://app.intigriti.com/programs/nvidia/nvidiavdp/detail).
diff --git a/plugins/nvidia-skills/skills/cuopt-user-rules/skill.oms.sig b/plugins/nvidia-skills/skills/cuopt-user-rules/skill.oms.sig new file mode 100644 index 00000000..e8886de5 --- /dev/null +++ b/plugins/nvidia-skills/skills/cuopt-user-rules/skill.oms.sig @@ -0,0 +1 @@ +{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json","verificationMaterial":{"x509CertificateChain":{"certificates":[{"rawBytes":"MIICgzCCAgmgAwIBAgIUKIyS7SxNteQIiWzK1dWj85E6520wCgYIKoZIzj0EAwMwVTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjEpMCcGA1UEAwwgTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBJQ0EgMDEwHhcNMjYwNDAxMDAwMDAwWhcNMjgwNDIyMTUzMzA5WjBUMQswCQYDVQQGEwJVUzEbMBkGA1UECgwSTlZJRElBIENvcnBvcmF0aW9uMSgwJgYDVQQDDB9OVklESUEgQWdlbnQgU2tpbGxzIFNpZ25pbmcgMDAxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEYoRM9bQl/dGlwSRNi6bTpIJUXH8Nv9GciP6LSflJYYMLCc296kpyuTSsk5ddbAWiDcFX3C/ydX3jwc+qCLYP6uHy9XphyLjOQ27Yb2J6rBLVtRBS1mgGco/Gr7fL6ODco4GaMIGXMB0GA1UdDgQWBBRQ/5ZW3nJ6lmo9SVk7I15o7UGmpTAfBgNVHSMEGDAWgBRPGpILxMBBleJSsBGjrMKsby1CgjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIHgDA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9vY3NwLm5kaXMubnZpZGlhLmNvbTAKBggqhkjOPQQDAwNoADBlAjAUygu/GiOCIXrgGr4SmLgeEVDcEitfFUv7ALbvLVGVyMysB3mxmO/uInZfXzWcJZsCMQDxuoxj4ZmO30jhkPIcCxGFCOvnUsnfU3TfGcouYm4M6iRpbKvtVnHPiy4bi6pcKf0="},{"rawBytes":"MIICiDCCAg6gAwIBAgIUZsIuSv9NkpJCNqtYEfCouVv5BzowCgYIKoZIzj0EAwMwUTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBDQTAgFw0yNjA0MDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowVTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjEpMCcGA1UEAwwgTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBJQ0EgMDEwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASI72cR3ctKGg4VWnB3bNja6g1Z2PnOmFEopkPof+QeIcPk9rT+g9MjJnq51EQXL93a7C2GJ9J985G4o2V85VD7wJ1RaXhluHW2rf3y8bQGeAYaKMr5s/hUgn+M3/9WlWejgaAwgZ0wHQYDVR0OBBYEFE8akgvEwEGV4lKwEaOswqxvLUKCMB8GA1UdIwQYMBaAFItnoAjjfuCEUvzyvWyI2vOGvwPjMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AubmRpcy5udmlkaWEuY29tMAoGCCqGSM49BAMDA2gAMGUCMQCeIMMfAbyzPDacw2MxG+Yt1cikrJX/DVxiGfXuHmkkXn6VgSzE79+lkqDErpVO2gYCMCNEColOyvUvkzZGUEI1hQ3PfMgi3FIo9tHoBKMw4/wGBLFpu/0ubtmbBXM6/UMOEw=="},{"rawBytes":"MIICRTCCAcygAwIBAgIUeJdY3rV86EdvFmG7L8LJBsyQFYkwCgYIKoZIzj0EAwMwUTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBDQTAgFw0yNjA0MDEwMDAwMDBaGA85OTk5MTIzMTIzNTk1OVowUTELMAkGA1UEBhMCVVMxGzAZBgNVBAoMEk5WSURJQSBDb3Jwb3JhdGlvbjElMCMGA1UEAwwcTlZJRElBIEFnZW50IENhcGFiaWxpdGllcyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABAYpiXCDjJ9NT2eSDhyHJVSw1Tbze18cGG2F/578oWvHxg23eQAhNRYdq88i1iOshZSO6C29doKui5Xpmo/7Ctw9Sx4PP2RzOmIuOLCuTdNtKcTRwi4GEsd5BAFvWj42M6NjMGEwHQYDVR0OBBYEFItnoAjjfuCEUvzyvWyI2vOGvwPjMB8GA1UdIwQYMBaAFItnoAjjfuCEUvzyvWyI2vOGvwPjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cAMGQCMCwtAjWLaNwgGWNCgdyNoTyvNhqWRECRJV2r3+7w8g0PL6NHLOsbkgE09BH95h8XlgIwTaQmbbUh2ChAJ5TA1wRiVDnCcvbzHlZl2jM2FcwQQZlk19LOAbyGMRixbu2Ww/rj"}]},"tlogEntries":[]},"dsseEnvelope":{"payload":"ewogICJfdHlwZSI6ICJodHRwczovL2luLXRvdG8uaW8vU3RhdGVtZW50L3YxIiwKICAic3ViamVjdCI6IFsKICAgIHsKICAgICAgIm5hbWUiOiAiY3VvcHQtdXNlci1ydWxlcyIsCiAgICAgICJkaWdlc3QiOiB7CiAgICAgICAgInNoYTI1NiI6ICJiNDdhNDEyMWE0OGY5M2VmNzU3Y2ZjODc4ZDUwOTY4YTRmZTcxNTE2MDBjNDFjMTMyOWU3ZGEzZTUxNTRmMzRkIgogICAgICB9CiAgICB9CiAgXSwKICAicHJlZGljYXRlVHlwZSI6ICJodHRwczovL21vZGVsX3NpZ25pbmcvc2lnbmF0dXJlL3YxLjAiLAogICJwcmVkaWNhdGUiOiB7CiAgICAic2VyaWFsaXphdGlvbiI6IHsKICAgICAgIm1ldGhvZCI6ICJmaWxlcyIsCiAgICAgICJoYXNoX3R5cGUiOiAic2hhMjU2IiwKICAgICAgImFsbG93X3N5bWxpbmtzIjogZmFsc2UsCiAgICAgICJpZ25vcmVfcGF0aHMiOiBbCiAgICAgICAgIi5naXRpZ25vcmUiLAogICAgICAgICIuZ2l0aHViIiwKICAgICAgICAiLmdpdCIsCiAgICAgICAgIi5naXRhdHRyaWJ1dGVzIgogICAgICBdCiAgICB9LAogICAgInJlc291cmNlcyI6IFsKICAgICAgewogICAgICAgICJhbGdvcml0aG0iOiAic2hhMjU2IiwKICAgICAgICAiZGlnZXN0IjogImMxNzUzOWMyYjVlNDFmNzRkNzk4ZTZhMmUyMTQzM2JhZDEyZTc0YjEyM2QyNjExMTFjODU0ZjliMTg0OTMyYmUiLAogICAgICAgICJuYW1lIjogIlNLSUxMLm1kIgogICAgICB9LAogICAgICB7CiAgICAgICAgImFsZ29yaXRobSI6ICJzaGEyNTYiLAogICAgICAgICJkaWdlc3QiOiAiMWZjYzMzMmMzYTMwNGRkYTI0NjVhMWViNGU4ZGUyZDY4OWVlNWNkZDkwYzkxYTk1NmY0OTAzZTZjMjdhZDBiNSIsCiAgICAgICAgIm5hbWUiOiAic2tpbGwtY2FyZC5tZCIKICAgICAgfQogICAgXQogIH0KfQ==","payloadType":"application/vnd.in-toto+json","signatures":[{"sig":"MGQCMDIjBmRHpcspsQ7/mEhz0qJSitSds+MN5Judmm28hW2/Dv35RN/+CwhoJ1iIRcCEpgIwGpgw2wwIBWcdWKaJ79Jy9JM1pzBXC0ajaGZJ/FKzP2gat3NDljl6ZFnzOxQnEieV","keyid":""}]}} \ No newline at end of file From 56b80d680f4f8ed4247e49df95e5b417f1d0834a Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 17:43:28 -0400 Subject: [PATCH 10/11] ci(plugins): make build resilient to upstream sync churn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes so copy-mode plugins (the default) coexist with the daily skills sync without manually rebuilding the plugin tree: 1. .github/scripts/build-plugins.py — soft-fail include_skills entries that the daily sync can legitimately invalidate: * include_skills path missing on disk (rename / removal) * path not a directory (rare upstream change) * no SKILL.md under a curated path (compliance enforcement dropped every skill) * duplicate skill basename across entries (rename collision) Each emits a loud "warning: ... skipping" log line and the build continues. Plugin ships with whatever curated skills actually resolved. Static config errors (bad yaml, invalid skill_files mode, etc.) still hard-fail. 2. .github/workflows/sync-skills.yml — run build-plugins.sh after the compliance-enforcement step and before regenerate-readme, so the sync PR ships a refreshed plugin tree alongside the skills/ updates. Mark "plugin catalog" as a changed component when the rebuild produced a diff so the PR summary surfaces it and the has_changes gate fires. Net effect: - Copy-mode plugins stay in sync with the canonical catalog automatically; validate-plugins.yml --check no longer trips on the daily sync. - Renames / compliance drops in upstream skills do not block the sync PR — they surface as warnings and as a curation-debt entry in plugins.d/.yml that a maintainer can reconcile in a follow-up. Signed-off-by: Jason Dudash --- .github/scripts/build-plugins.py | 33 ++++++++++++++++++++++++++----- .github/workflows/sync-skills.yml | 25 +++++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/.github/scripts/build-plugins.py b/.github/scripts/build-plugins.py index 1d6a8441..c24b167a 100755 --- a/.github/scripts/build-plugins.py +++ b/.github/scripts/build-plugins.py @@ -125,15 +125,29 @@ def expand_skill_paths(entries: list[str]) -> list[tuple[str, Path]]: - "skills/cuopt/cuopt-install/" → [("cuopt-install", REPO/skills/cuopt/cuopt-install)] - "skills/cuopt/" → all immediate children of skills/cuopt that contain SKILL.md + + Soft-fails any entry that would otherwise abort the build because of an + upstream catalog change (rename, removal, compliance-driven SKILL.md + drop, basename collision). The plugin ships with whatever curated + skills DID resolve, the warnings are surfaced in stdout, and the daily + sync PR is not blocked by curation drift in plugins.d/.yml. + Hard config errors (bad YAML, invalid plugin name, etc.) still die. """ out: list[tuple[str, Path]] = [] for entry in entries: rel = entry.rstrip("/") src = (REPO_ROOT / rel).resolve() if not src.exists(): - die(f"include_skills entry not found: {entry}") + log( + f" ! warning: include_skills entry missing on disk, skipping: {entry} " + f"(upstream rename/removal? update plugins.d/.yml)" + ) + continue if not src.is_dir(): - die(f"include_skills entry is not a directory: {entry}") + log( + f" ! warning: include_skills entry is not a directory, skipping: {entry}" + ) + continue skill_md = src / "SKILL.md" if skill_md.is_file(): out.append((src.name, src)) @@ -145,13 +159,22 @@ def expand_skill_paths(entries: list[str]) -> list[tuple[str, Path]]: out.append((child.name, child)) found += 1 if found == 0: - die(f"no SKILL.md found under {entry}") + log( + f" ! warning: no SKILL.md under {entry}, skipping " + f"(compliance enforcement may have dropped every skill here)" + ) seen: dict[str, Path] = {} + deduped: list[tuple[str, Path]] = [] for name, src in out: if name in seen and seen[name] != src: - die(f"duplicate skill name '{name}': {seen[name]} vs {src}") + log( + f" ! warning: duplicate skill basename {name!r} across " + f"include_skills, keeping first: {seen[name]} (dropping {src})" + ) + continue seen[name] = src - return out + deduped.append((name, src)) + return deduped VALID_MATERIALIZATIONS = ("copy", "symlink") diff --git a/.github/workflows/sync-skills.yml b/.github/workflows/sync-skills.yml index a4d59711..545076d8 100644 --- a/.github/workflows/sync-skills.yml +++ b/.github/workflows/sync-skills.yml @@ -255,6 +255,31 @@ jobs: echo "Opened new tracking issue" fi + - name: Rebuild plugin catalog + run: | + set -euo pipefail + # plugins//skills/ in copy mode duplicates content from + # the canonical skills/ tree, so any sync that touched a + # curated source path leaves those copies stale. Re-run the + # plugin build here so the same sync PR ships a consistent + # tree (skills/ + plugins/) and validate-plugins.yml --check + # stays green. Symlink-mode plugins are a no-op for the build. + # build-plugins.py soft-fails missing/dropped curated skills + # so a rename or compliance drop does NOT block the sync PR. + .github/scripts/build-plugins.sh + + # Mark the plugin catalog as a changed component if anything + # under plugins/ or either marketplace.json moved, so the PR + # summary surfaces it and the "has_changes" gate fires even + # when the only diff is the auto-rebuild. + if ! git diff --quiet plugins/ \ + .claude-plugin/marketplace.json \ + .agents/plugins/marketplace.json; then + if ! grep -qx "- plugin catalog" /tmp/changed-components.txt 2>/dev/null; then + echo "- plugin catalog" >> /tmp/changed-components.txt + fi + fi + - name: Regenerate README tables run: .github/scripts/regenerate-readme.sh From 81a355ed04523d52c8bfa1b046b49885df91e847 Mon Sep 17 00:00:00 2001 From: Jason Dudash Date: Tue, 26 May 2026 18:01:37 -0400 Subject: [PATCH 11/11] ci(plugins): soft-fail more recoverable build errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert six previously-fatal die() sites to error-or-warning logs that let the build continue past per-plugin misconfigurations. The principle matches the expand_skill_paths soft-fail introduced in e6335f0: one bad input no longer takes down the whole catalog. Helpers: error() non-exiting stderr logger (companion to die()) read_yaml_lenient() parse-or-None YAML reader for per-plugin files Sites converted (build_plugins.py): A. read_yaml() malformed → log + skip file B. invalid skill_files= → warning + fallback to "copy" C. plugin name not kebab-case → log + skip plugin (moved into discover so the bad entry never enters the catalog dict) D. curated .skills-manifest.yml empty → warning + materialize empty skills/ tree E. missing 'name' in plugins.d file → log + skip file F. duplicate plugin name across → log + first-alphabetically plugins.d/ wins, the rest are skipped (matches expand_skill_paths) Sites kept as die() (structural / guard / manual-invocation): - read_yaml(_defaults.yml) - missing .claude-plugin/marketplace.json - missing .agents/plugins/marketplace.json - --only NAME with no match - --check drift detection Smoke-tested all six locally: each malformed input emits a loud error/warning line and the build still completes with the rest of the catalog intact. Signed-off-by: Jason Dudash --- .github/scripts/build-plugins.py | 88 +++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 12 deletions(-) diff --git a/.github/scripts/build-plugins.py b/.github/scripts/build-plugins.py index c24b167a..ebe7bdcf 100755 --- a/.github/scripts/build-plugins.py +++ b/.github/scripts/build-plugins.py @@ -89,7 +89,17 @@ def die(msg: str, code: int = 1) -> None: sys.exit(code) +def error(msg: str) -> None: + """Like die() but does not exit. For recoverable per-item failures + that should be loud in logs but not block the rest of the build.""" + print(f"error: {msg}", file=sys.stderr, flush=True) + + def read_yaml(path: Path) -> dict[str, Any]: + """Strict YAML read — dies on parse error or non-mapping root. + Use for files whose absence/corruption is structural (e.g. + plugins.d/_defaults.yml). For per-plugin yaml files, prefer + read_yaml_lenient so one bad file does not block the rest.""" with path.open() as f: data = yaml.safe_load(f) if not isinstance(data, dict): @@ -97,6 +107,24 @@ def read_yaml(path: Path) -> dict[str, Any]: return data +def read_yaml_lenient(path: Path) -> dict[str, Any] | None: + """Soft YAML read — returns None on parse error or non-mapping root, + logs an error to stderr. Caller decides whether to skip the file.""" + try: + with path.open() as f: + data = yaml.safe_load(f) + except yaml.YAMLError as e: + error(f"{path}: YAML parse error: {e}") + return None + if not isinstance(data, dict): + error( + f"{path}: expected a YAML mapping at top level, got " + f"{type(data).__name__}" + ) + return None + return data + + def read_json(path: Path) -> Any: with path.open() as f: return json.load(f) @@ -208,10 +236,11 @@ def materialize_skills( NOT supported by Codex local marketplace install. """ if mode not in VALID_MATERIALIZATIONS: - die( - f"plugin {plugin_name!r}: invalid skill_files={mode!r} " - f"(allowed: {', '.join(VALID_MATERIALIZATIONS)})" + log( + f" ! warning: plugin {plugin_name!r}: invalid skill_files={mode!r}, " + f"falling back to 'copy' (allowed: {', '.join(VALID_MATERIALIZATIONS)})" ) + mode = "copy" plugin_dir = PLUGINS_DIR / plugin_name target = plugin_dir / "skills" if target.is_symlink() or target.exists(): @@ -324,9 +353,9 @@ def render_codex_plugin_json(spec: dict[str, Any]) -> dict[str, Any]: def build_catalog_plugin(spec: dict[str, Any]) -> str: + # `name` is already validated for kebab-case + uniqueness in discover() + # before specs reach this function. name = spec["name"] - if not re.fullmatch(r"[a-z0-9][a-z0-9-]*", name): - die(f"plugin name must be lowercase kebab-case: {name!r}") plugin_dir = PLUGINS_DIR / name plugin_dir.mkdir(parents=True, exist_ok=True) log(f"── catalog plugin: {name} ──") @@ -356,20 +385,34 @@ def build_catalog_plugin(spec: dict[str, Any]) -> str: # ---------------------------- curated plugin --------------------------------- -def build_curated_plugin(plugin_dir: Path) -> str: +def build_curated_plugin(plugin_dir: Path) -> str | None: """ A curated plugin is one with plugins//.skills-manifest.yml but no plugins.d/.yml. We rebuild only its skills/ tree (mode selected by `skill_files:` in the manifest, default `copy`) and trust everything else to be hand-maintained. + + Returns the plugin name on success, or None if we skipped the build + due to a malformed manifest. The marketplace upsert preserves the + plugin's existing entry verbatim either way. """ manifest_path = plugin_dir / ".skills-manifest.yml" - spec = read_yaml(manifest_path) name = plugin_dir.name + spec = read_yaml_lenient(manifest_path) + if spec is None: + error( + f" ! skipping curated plugin {name!r} — " + f"{manifest_path.relative_to(REPO_ROOT)} is unreadable; " + f"existing plugins/{name}/skills/ left untouched" + ) + return None log(f"── curated plugin: {name} ──") skills = spec.get("skills") or [] if not skills: - die(f"{manifest_path}: 'skills' list is empty") + log( + f" ! warning: {manifest_path.relative_to(REPO_ROOT)} has empty " + f"'skills' list; producing empty plugins/{name}/skills/" + ) mode = spec.get("skill_files", "copy") materialize_skills(name, skills, mode=mode) return name @@ -458,23 +501,44 @@ def merge_with_defaults(defaults: dict[str, Any], plugin: dict[str, Any]) -> dic def discover() -> tuple[dict[str, dict[str, Any]], list[Path]]: + # _defaults.yml is structural (every plugin merges from it); a parse + # failure there makes downstream merges meaningless, so keep strict. defaults: dict[str, Any] = {} if PLUGINS_D_DEFAULTS.is_file(): defaults = read_yaml(PLUGINS_D_DEFAULTS) + # Per-plugin yaml files are validated leniently: one bad/duplicate/ + # unnamed file logs an error and gets skipped; the rest of the + # catalog still builds. catalog: dict[str, dict[str, Any]] = {} if PLUGINS_D.is_dir(): for ymlfile in sorted(PLUGINS_D.glob("*.yml")): if ymlfile.name.startswith("_"): continue - plugin_spec = read_yaml(ymlfile) + rel = ymlfile.relative_to(REPO_ROOT) + plugin_spec = read_yaml_lenient(ymlfile) + if plugin_spec is None: + error(f" ! skipping {rel} — YAML errors above") + continue spec = merge_with_defaults(defaults, plugin_spec) name = spec.get("name") if not name: - die(f"{ymlfile}: missing 'name'") + error(f"{rel}: missing 'name', skipping") + continue + if not re.fullmatch(r"[a-z0-9][a-z0-9-]*", name): + error( + f"{rel}: plugin name {name!r} is not lowercase " + f"kebab-case, skipping" + ) + continue if name in catalog: - die(f"duplicate plugin name '{name}' across plugins.d/") - spec["__source"] = str(ymlfile.relative_to(REPO_ROOT)) + first = catalog[name].get("__source", "?") + error( + f"{rel}: duplicate plugin name {name!r} (already " + f"declared in {first}), skipping" + ) + continue + spec["__source"] = str(rel) catalog[name] = spec curated: list[Path] = []