{"slug": "translating-cuda-tile-operations-from-python-to-rust-using-agentic-ai", "title": "Translating CUDA Tile Operations from Python to Rust Using Agentic AI", "summary": "NVIDIA Labs built an AI agent skill that translated all 24 public TileGym operators from cuTile Python and Triton-TileIR into cuTile Rust, reaching 99.5% of cuTile Python performance on average across roughly 40 GPU kernels. The multi-agent pipeline covers analysis, device kernel, host and FFI code, and benchmarking, with validator scripts and Tile IR diffs deciding whether each conversion proceeds. The skill ships in the TileGym repository so developers can apply it to their own kernels.", "body_md": "[cuTile Rust](https://github.com/nvlabs/cutile-rs) (`cutile-rs`) is a tile-based system for safe, idiomatic GPU kernel authoring in the Rust programming language. Extending the Rust ownership model to tile-based GPU kernels, it splits mutable outputs into disjoint pieces and preserves the host-side ownership contract across kernel launches. It also allows programmers to opt out locally when they need lower-level control, enabling direct execution of Tile IR operations.\n\nThe TileGym CUDA tile kernel library has accumulated a large library of production kernels written in CUDA Tile Python ([cuTile Python](https://github.com/NVIDIA/cutile-python)) and [Triton-TileIR](https://github.com/triton-lang/Triton-to-tile-IR) (`nvtriton`). To make all of these kernels available in Rust as well, our team built an [AI agent](https://www.nvidia.com/en-us/ai/) skill that translates cuTile Python and Triton-TileIR kernels into cuTile Rust. \n\nUsing this skill, we ported all 24 public TileGym operators to cuTile Rust and reached 99.5% of cuTile Python performance on average. They contain roughly 40 GPU kernels in total, ranging from element-wise operations to flash-attention decode, Multi-head Latent Attention (MLA), and [mixture-of-experts (MoE)](https://www.nvidia.com/en-us/glossary/mixture-of-experts/) models. Note that some operators need multiple kernel variants.\n\nEach conversion starts from whichever reference implementation the operator has (cuTile Python or Triton-TileIR) and runs through a bounded multi-agent pipeline covering analysis, the device kernel, host and FFI code, and benchmarking. Every stage ends in a machine-checkable verdict, with validator scripts and Tile IR diffs deciding whether a conversion moves forward. The main challenge is that cuTile Python JIT compilation specializes each kernel implicitly at call time, whereas Rust requires that you declare every specialization in the kernel’s signature.\n\nThis post explains how we developed a multi-agent workflow to translate cuTile Python and Triton-TileIR kernels into cuTile Rust, with checks for correctness and performance at each stage. It covers what the gap looks like in a real kernel, how the skill is structured so that no stage has to be taken on trust, and how the resulting kernels perform against their references. The skill ships in the TileGym repo, so you can apply it to your own kernels.\n\n## Kernel translation between Tile IR front ends\n\ncuTile Python, Triton-TileIR, and cuTile Rust are three front ends over the same IR: [CUDA Tile IR](https://github.com/NVIDIA/cuda-tile), the `cuda_tile` dialect. All three feed the same `tileiras` compiler, which performs the tile-level optimizations and emits the GPU binary. This shared foundation makes translating across the CUDA Tile family practical and, just as important, verifiable.\n\n```\ncuTile Python ─┐\nTriton-TileIR ─┼─► CUDA Tile IR (cuda_tile dialect) ─► tileiras ─► cubin\ncuTile Rust   ─┘\n```\n\nThe TileGym production tile kernels are written against the first two front ends. Because all three meet at the same IR, porting a kernel to cuTile Rust is not a re-optimization problem. It is re-expressing the same tile program in a safer host language, with the same compiler and the same performance model underneath. The shared IR makes translation checkable.\n\nA faithful port should reproduce the reference kernel’s IR structure: the same memory-op families, same tile shapes, and same reductions. Because all three front ends emit the same dialect, this can be directly verified by dumping the reference kernel Tile IR and the translated kernel Tile IR and “diffing” them before a single test is executed.\n\nThis enables checking the agent’s output structurally, not just functionally. A wrong-but-plausible translation (a TMA load with wrong cost hint or a dropped divisibility attribute, for example) can pass tests yet still be incorrect outside of test coverage and may bring performance regressions. These issues can be easily checked and fixed by comparing with the reference IR. The IR diff stage is central to the pipeline described in this post.\n\nTwo additional aspects of the Rust front end are important to note for this discussion. First, the Rust source is compiled ahead of time. Tile shapes and element types are checked by `rustc`. The [crate](https://crates.io/crates/cutile/) embeds the kernel AST, and at first launch the runtime specializes it with the concrete const-generic values and compiles a cubin (cached thereafter). The GPU binary itself is still JIT-compiled, but the implicitness is gone: nothing is specialized unless the kernel signature declares it. Second, in TileGym, cuTile Rust is simply another backend. `tilegym.set_backend(\"cutile-rs\")` routes the same operator API to the Rust kernels.\n\n### Making specialization explicit\n\nThe two front ends differ in where specialization happens. cuTile Python JIT specializes on whatever it sees at call time. cuTile Rust specializes only on what the kernel signature declares. Most of the translation work comes from spelling out what the Python source leaves implicit. The main cases are summarized in the following table.\n\n| **cuTile Python (implicit JIT)** | **cuTile Rust (AOT Rust source)** | **Consequence for translation** | \n|---|---|---|\n| Untaken if `ct.Constant` branches are dropped before compilation | Both branches must type-check | One Python kernel becomes multiple structural Rust entries (for example, `layer_norm` splits into 2-D`nchw` and 1-D`w1` entries because the branch changes tile rank) | \n| Any `dtype` combination compiles on demand | The FFI dispatches over a fixed `symbol/dtype` table | Supporting a `dtype` is an explicit ABI extension; the shared table spans`f32/f16/bf16/i32/i64/f8e5m2/f8e4m3fn` | \n| The JIT type system is the input validation | Past the C ABI there is no safety net, so a wrong stride is a silent corruption, not an exception | Two defensive layers: semantic checks in the Python wrapper, ABI checks ( `null/dtype/device` ) behind the FFI with named return codes | \n\n*Table 1. Examples of cuTile Python-Rust translation gaps*\n\nThe following section illustrates these differences using a real kernel example.\n\n## Softmax translation example\n\nThis example kernel is intentionally simple so you can compare the two versions line by line. First, in cuTile Python:\n\n``` python\n@ct.kernel\ndef softmax_kernel(output, input, TILE_SIZE: Constant[int]):\n    row_idx = ct.bid(0)                       # one CTA per row\n\n    row = ct.load(input, index=(row_idx, 0), shape=(1, TILE_SIZE),\n                  padding_mode=ct.PaddingMode.NEG_INF)\n    row = ct.astype(row, ct.float32)\n\n    row_max = ct.max(row, axis=1, keepdims=True)\n    numerator = ct.exp(row - row_max)\n    denominator = ct.sum(numerator, axis=1, keepdims=True)\n    out = numerator / denominator\n\n    out = ct.astype(out, input.dtype)\n    ct.store(output, index=(row_idx, 0), tile=out)\n```\n\nAnd the same kernel in cuTile Rust:\n\n```\n#[cutile::module]\npub mod softmax_module {\n    use cutile::core::*;\n\n    #[cutile::entry()]\n    pub fn softmax_kernel<E: ElementType, const TILE_SIZE: i32>(\n        output: &mut Tensor<E, { [1, TILE_SIZE] }>,   // one row per CTA\n        input: &Tensor<E, { [-1, -1] }>,\n    ) {\n        let row_idx = get_tile_block_id().0;          // ct.bid(0)\n\n        // ct.load(..., padding_mode=NEG_INF): a safe partition view whose ragged\n        // columns pad with -inf, then a load of this CTA's row.\n        let token: Token = get_tensor_token(input);\n        let row_view: Partition<E, { [1, TILE_SIZE] }> = make_partition_view(\n            input, const_shape![1, TILE_SIZE], padding::NegInf, dim_map::Identity, token);\n        let row: Tile<E, { [1, TILE_SIZE] }> = row_view.load([row_idx, 0i32]);\n        let row: Tile<f32, { [1, TILE_SIZE] }> = convert_tile(row);   // ct.astype(f32)\n\n        let row_max: Tile<f32, { [1] }> = reduce_max(row, 1i32);\n        let shifted = row - row_max.reshape(const_shape![1, 1])\n                                   .broadcast(const_shape![1, TILE_SIZE]);\n        let numerator: Tile<f32, { [1, TILE_SIZE] }> = exp(shifted);\n\n        let denominator: Tile<f32, { [1] }> = reduce_sum(numerator, 1i32);\n        let out = numerator / denominator.reshape(const_shape![1, 1])\n                                         .broadcast(const_shape![1, TILE_SIZE]);\n\n        let out: Tile<E, { [1, TILE_SIZE] }> = convert_tile(out);     // ct.astype(dtype)\n        output.store(out);                                            // ct.store\n    }\n}\n```\n\nYou can read the correspondences directly. They’re this clean because both front ends are thin surfaces over the same Tile IR ops:\n\n- `Constant[int]` parameters become const generics (`const TILE_SIZE: i32` ), instantiated per launch shape by the host through the same Tile IR JIT.\n- `ct.load(..., padding_mode=NEG_INF)` becomes two explicit steps. First build a`make_partition_view(..., padding::NegInf, ...)` , then a`Partition::load` —the same TMA-backed view load that the reference IR contains, with the ragged tail padded to`-inf` .\n- `ct.bid(0)` maps to`get_tile_block_id()` .\n- What cuTile Python keeps implicit becomes an explicit type. Every intermediate is a `Tile<f32, {[1, TILE_SIZE]}>` , and a`keepdims=True` reduction becomes a`reduce_*` followed by an explicit`reshape` and`broadcast` .\n\nThe IR diff then confirms that Rust compiles to the same op inventory as the Python original: one view load, `reduce_max/reduce_sum` on the right axis, one view store, and TMA on both ends. Note that not all of the shipped kernels in TileGym use this fully safe style yet. Each port has to reproduce the reference kernel Tile IR exactly, so where only an unchecked API reproduces it, the port uses that API. We’re still migrating those kernels onto the safe surface shown in this post.\n\n## Crossing the C ABI\n\nThe example `kernel.rs` is already a complete, first-class cuTile Rust kernel. A Rust application can depend on the `cutile` crate, include the kernel module, and launch its entry directly through the crate typed API (ownership checks, tile types, and all) with no FFI involved.\n\nThe C-ABI layer serves a narrower purpose: plugging those kernels into the TileGym Python dispatch and test framework (and, by the same mechanism, any non-Rust host).\n\nEach operator exports one C symbol from the aggregated `cdylib` (one `libcutile_kernels.so` for the whole library). Tensors cross as a plain descriptor struct (`ptr, ndim, shape[], strides[]`) mirrored between Rust and Python:\n\n``` js\n#[unsafe(no_mangle)]\n pub unsafe extern \"C\" fn cutile_softmax(\n \tout: *const TensorDesc, inp: *const TensorDesc,\n     n_rows: i32, tile_size: i32, device_id: i32, raw_stream: u64,\n ) -> i32 {\n \tlet out_d = unsafe { &*out };\n\tlet inp_d = unsafe { &*inp };\n \tlet device = Device::new(device_id as usize).expect(\"device\");\n \tlet stream = unsafe { Stream::borrow_raw(raw_stream as *mut c_void, &device) };\n \tlet mut y = unsafe { borrow_f32(out_d, device_id as usize) };\n \tlet x = unsafe { borrow_f32(inp_d, device_id as usize) };\n \tlet y_part = (&mut *y).partition([1, tile_size as usize]);\n \tmatch softmax_kernel(y_part, &*x).sync_on(&stream) {\n     \tOk(_) => 0,\n     \tErr(_) => -1,\n \t}\n }\n```\n\nOn the Python side, `cffi` binds that symbol from a `cdef` string that is the single source of truth for the signature. The wrapper is a thin layer with validation checks:\n\n``` js\n_FFI_CDEF = \"\"\"\nint32_t cutile_softmax(\n\tconst TensorDesc* out, const TensorDesc* inp,\n\tint32_t n_rows, int32_t tile_size,\n    int32_t device_id, uint64_t raw_stream);\n\"\"\"\n\ndef softmax(x):\n\tx = x.contiguous(); m, n = x.shape\n\ty = torch.empty_like(x)\n\trc = lib.cutile_softmax(_desc(y), _desc(x), m, next_pow2(n),\n                        \t    x.device.index or 0,\n                               torch.cuda.current_stream().cuda_stream)\n\tassert rc == 0\n\treturn y\n```\n\nNote that the launcher never copies, never allocates, and never takes ownership. `borrow_f32` wraps the PyTorch device pointer in a `ManuallyDrop<Tensor>`, so Rust can hand the kernel its tensors without ever freeing memory it does not own, and the kernel launches asynchronously on the caller CUDA stream. From a PyTorch perspective, this looks like any other extension op.\n\nThis is also friction-free within TileGym, because cuTile Rust compiles lazily. The backend tracks source freshness, so editing any `kernel.rs` (or the crate manifest) makes the next call automatically rebuild the shared library before dispatch, with no explicit `cargo build` in the develop-test cycle. Iterating on a tile kernel in Rust is as easy as it is in Python: change the kernel, run the test, and the new binary is already in place.\n\n## How does the agent skill work?\n\nThe [tilegym-converting-python-to-rust agent skill](https://github.com/NVIDIA/TileGym/tree/main/skills/tilegym-converting-cutile-triton-to-cutile-rs), shipped in the [NVIDIA/TileGym](https://github.com/NVIDIA/TileGym/tree/main/skills/tilegym-converting-cutile-triton-to-cutile-rs) GitHub repo, is built around one design decision: the agent that loads it does no engineering work at all**.** Reading `SKILL.md` turns the top-level agent into a pure orchestrator whose only authority is routing; the work happens in specialized subagents it spawns, each loading only the reference documents its stage needs. We’ll walk through each subagent type and its role in the conversion.\n\nThe analyzer solves the “JIT hides the spec” problem. In a reference kernel, constants are baked in once the DSL lowers to the `cuda_tile` dialect, untaken branches vanish, and launch parameters live in host code. The analyzer also selects the baseline: an operator often has both a cuTile Python and a Triton-TileIR implementation, so the analyzer benchmarks each, compares them, and selects the faster one per structural variant as the reference the port must match.\n\nBefore any Rust exists, it dumps the Tile IR of that reference for each variant (the ground truth for the kernel writer) and writes `analysis.json`, a machine-readable spec of variants, constants, dtypes, tolerances, launch grids, autotune space, and the chosen baseline. Everything downstream routes from this file.\n\nThe kernel writer produces `kernel.rs` and nothing else. Barred from host code, its failures stay attributable. Its hard problem is the translation gap itself, distilled into the skill’s 49 coding rules. It proves its work twice. First functionally, with an in-Rust pipeline test that runs the kernel with no FFI and no Python, so a numerics bug can’t hide behind host plumbing. Second structurally, by clearing an IR self-check against the analyzer’s reference dump.\n\nThe host/FFI builder makes validated kernels callable from TileGym (the C-ABI launcher plus the Python wrapper) and owns the correctness checks, runs the operator’s real TileGym test suite across all dtypes and shapes, and only its `ALL_PASS` verdict unlocks benchmarking. This is the first point where the full stack (kernel, launcher, and wrapper) runs end-to-end.\n\nThe performance validator runs the CUPTI benchmark protocol (device-time measurement, per-config pairing against the reference on the same GPU) and requires the geometric mean to land within 5% of the reference. Its job is not to optimize but to measure honestly.\n\nTwo specialists join only on failure. Neither edits code; both diagnose by reading IR. The IR-diff analyst is spawned when a correctness test fails or a benchmark looks off. It diffs the reference Tile IR against the generated IR variant by variant and classifies each divergence. Crucially, this separates a mistranslation (route back to the kernel writer with a specific fix) from an upstream compiler bug that no kernel change can fix.\n\nThe residual-performance investigator takes a correct kernel that is slow on some input shapes and root-causes the gap on both sides of the boundary: the device side (memory-op family, codegen) and the host side (launch configuration, autotune, and wrapper logic). It emits a report that the kernel writer acts on.\n\nTwo key reasons motivate this design. First, a full conversion runs on the order of millions of tokens. Second, the split isolates blame. Because the kernel is proven in isolation before any host code exists, a later failure has a tractable owner.\n\nThree choices make this split work. Subagents communicate only through artifacts with fixed schemas, never through conversation. Each stage ends with a machine-checkable verdict the orchestrator routes on without reading prose. And the shared `cuda_tile` dialect makes IR diff the backbone of verification—used both as the kernel writer’s self-check before tests run and as the IR-diff analyst’s deep comparison when something fails—rejecting structurally wrong translations (a reduction on the wrong axis, a lost mask) that would otherwise pass as plausible.\n\n### **The orchestrator loop**\n\nA conversion run is a small state machine, and the orchestrator’s own instructions fit in a lean `SKILL.md`. The steps are detailed in Figure 1 and following.\n\n1. **Preflight:**`scripts/preflight.sh` verifies`env` vars and toolchain paths. A non-zero exit stops the run: the environment is unusable, and no amount of agent effort fixes a missing compiler.\n2. **Spawn with minimal pointers:** Every subagent is spawned from one template whose prompt contains only two elements: the stage Step-0 file list (its own instruction file plus the reference docs*that stage* needs) and the concrete paths of prior-stage artifacts. The orchestrator never pastes instructions into prompts. Each subagent reads its own files, so the context of each stage holds only what that stage needs.\n3. **Mechanical validator:** Every subagent return must end with a literal`<VALIDATOR_OUTPUT>` block and one`VERDICT:` line. The orchestrator checks the exit codes inside the block, then routes purely on the verdict; it never infers a fix from prose. A malformed return earns exactly one same-agent repair respawn, never an escalation.\n4. **Route by table:** Figure 1 is the whole decision function. Verdicts advance the green path, failure routes carry a machine-readable owner tag (`host` → the builder respawns itself;`kernel` → the IR-diff analyst assigns the owner;`env` → stop), and a failed perf benchmark routes once through the residual-perf investigator. A missing owner tag is itself a failure. The orchestrator stops rather than guessing because a host fault misrouted to the kernel stage wastes an entire retry.\n5. **Hard spawn caps:** The xN in each box of Figure 1 caps the attempts (one analysis, two kernel-writer and two host-builder attempts, one diagnosis, two benchmark runs, and one optional perf pass). A run either converges within the budget or stops with a diagnosis on disk; it cannot thrash.\n6. **Final aggregate:** Only after the route reaches completion does`validate_kernel.sh` recheck the full 17-file output contract across all stages: reports, IR dumps, correctness, and performance logs.\n\nOn disk, the skill packages each agent’s role, the shared knowledge, and the validators separately, so every subagent loads only what it needs:\n\n```\nskills/tilegym-converting-python-to-rust/\n├── SKILL.md                  \t# entry point + orchestration contract\n├── agents/*.md               \t# one instruction file per stage\n├── references/\n│   ├── coding-rules.md       \t# numbered rules (each from a real failure)\n│   ├── op-mapping.md         \t# ct.* -> cutile-rs API table\n│   ├── ir-diff-checklist.md  \t# what counts as a critical IR divergence\n│   ├── pipeline.md           \t# in-Rust pipeline test harness\n│   └── performance-checklist.md  # benchmark protocol\n├── concepts/                 \t# tensor-vs-pointer, FFI bridge, transpose\n├── scripts/                  \t# diff_ir.sh + validate_*.sh per agent\n└── examples/{softmax,bmm}/   \t# two fully worked conversions\n```\n\nThe coding rules are the distilled failure history. Each one exists because an early conversion produced a kernel that compiled but was wrong without it. They range from the narrow to the structural: `assume_div_by` applies only to pointers and never to `Tensor` entries, a broadcast must be preceded by a reshape, and reduction-axis bookkeeping must be exact for every tile rank.\n\n### **How the harness takes effect**\n\nThree layers turn the markdown into a running system: activation, contracts, and the outer driver.\n\n**Activation:** The runtime activates the skill by matching a task against its description (“convert, port, or translate Triton-TileIR or cuTile Python GPU kernels to cuTile Rust”). On match, the top-level agent loads `SKILL.md` *only*, a lean file that turns it into the orchestrator. It never reads the subagent files; those load inside the subagents themselves, alongside just the reference documents their stage needs.\n\n**Contracts:** Between layers, everything is a file or a fixed-format string. Spawn prompts are minimal pointers, stage outputs are artifacts with schemas, and returns are a validator block plus a verdict line. The entire authority of the orchestrator is routing, and the entire authority of the validator scripts is exit codes. Nothing in the loop depends on one LLM interpreting the prose of another LLM. This is what makes 24 unattended conversions repeatable rather than lucky.\n\n**The outer driver:** In production, a one-shot driver wraps the skill to make each conversion a hands-off batch job. It creates a fresh checkout on a per-operator branch, hides any pre-existing implementation of the target operator (so the agent must translate), launches the agent in a container detached from the operator’s terminal, and polls progress from outside. When the run ends, the driver applies the captured repo diff and runs the acceptance check: TileGym correctness is green, proof that the cuTile Rust backend actually executed, and CUPTI geomean speedup ≥ 0.95 against the cuTile Python baseline. Only a green outcome autocommits. A thin batch driver runs the operator list with at most two attempts each and pushes the branches that pass; failed conversions land as a diagnosis trail.\n\n## **Benchmarking results**\n\nWith the tilegym-converting-python-to-rust skill, kernel conversion becomes far more efficient. Token cost drops to about half on average, every operator is validated for numerical correctness, and each one hits a geomean speedup of ≥0.95 versus cuTile Python. The final performance numbers come from the CI benchmark pipeline itself: CUPTI device time on [NVIDIA DGX B200](https://www.nvidia.com/en-us/data-center/dgx-b200/) (one exclusive GPU per backend, 347 paired configurations across the 24 operators). For each configuration, the best measurement is taken across four CI runs.\n\nOverall geomean is 0.995, parity with cuTile Python. The shared-IR architecture primarily explains these results. Both front ends feed the same tile program into a shared optimizer, and a faithful translation inherits the reference’s performance by construction. All 24 operators clear the 0.95 check, and about a third come out ahead of the reference, with the largest wins on element-wise and normalization kernels. Each conversion lands as a standard six-file changeset, so review stays mechanical.\n\nFigure 2 reports CUPTI device time, which isolates the kernel itself. Wall-clock time and device time answer different questions on submicrosecond kernels. Wall-clock time includes launch and scheduling cost and reflects what the user experiences, while CUPTI device time compares the kernels in isolation. We measure wall clock and report device time to keep the operator-to-operator comparison about the kernels.\n\ncuTile Rust can also emit Tile IR directly. The DSL exposes the Tile IR instruction set as part of its unsafe API surface. In principle, you could write a kernel to match the Tile IR emitted by other front ends exactly. However, such kernels become uninterpretable, so the skill is biased to generate idiomatic code. Because the experiments capture only device time, we expect that matching the emitted Tile IR exactly would match performance exactly across front ends.\n\n## Get started with cuTile Rust agent skills\n\nThe agent skill that translates cuTile Python and Triton-TileIR kernels into cuTile Rust and all converted operators ships with TileGym. Access the skill through [skills/tilegym-converting-python-to-rust/](https://github.com/NVIDIA/TileGym/tree/main/skills/tilegym-converting-cutile-triton-to-cutile-rs). It includes per-stage agent instructions, a coding rulebook, concept guides, validator scripts, and worked softmax and bmm examples. Access the kernels through [`src/tilegym/ops/cutile_rs/`](https://github.com/NVIDIA/TileGym/tree/main/src/tilegym/ops/cutile_rs), including one `<op>_kernel/` per operator plus the aggregated `cutile_kernels` crate. Requirements: CUDA 13.1+, a Blackwell GPU for the perf check, Rust 1.89+, and the `tileiras` compiler.\n\nTo get started, point any agent at the repo and ask it to “add a cutile-rs backend for `<op>`“. The pipeline handles analysis, kernel, FFI, correctness, and benchmarking. For more details refer to the [TileGym README](https://github.com/NVIDIA/TileGym#5-enable-the-cutile-rs-rust-backend-optional) on GitHub.", "url": "https://wpnews.pro/news/translating-cuda-tile-operations-from-python-to-rust-using-agentic-ai", "canonical_source": "https://developer.nvidia.com/blog/translating-cuda-tile-operations-from-python-to-rust-using-agentic-ai/", "published_at": "2026-09-16 16:28:59+00:00", "updated_at": "2026-09-16 16:45:20.871089+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-research"], "entities": ["NVIDIA Labs", "cuTile Rust", "cuTile Python", "Triton-TileIR", "TileGym", "CUDA Tile IR", "tileiras", "Tile IR"], "alternates": {"html": "https://wpnews.pro/news/translating-cuda-tile-operations-from-python-to-rust-using-agentic-ai", "markdown": "https://wpnews.pro/news/translating-cuda-tile-operations-from-python-to-rust-using-agentic-ai.md", "text": "https://wpnews.pro/news/translating-cuda-tile-operations-from-python-to-rust-using-agentic-ai.txt", "jsonld": "https://wpnews.pro/news/translating-cuda-tile-operations-from-python-to-rust-using-agentic-ai.jsonld"}}