Skip to content

Generative

Spike-driven generative models: audio synthesis from neural activity, text generation via spiking language models, and 3D mesh generation.

Audio Synthesis

sc_neurocore.generative.audio_synthesis

SCAudioSynthesizer dataclass

SC Audio Synthesis engine. Converts bitstreams/probabilities to waveform buffers.

Source code in src/sc_neurocore/generative/audio_synthesis.py
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@dataclass
class SCAudioSynthesizer:
    """
    SC Audio Synthesis engine.
    Converts bitstreams/probabilities to waveform buffers.
    """

    sample_rate: int = 44100

    def synthesize_tone(
        self, frequency: float, duration_ms: int, probability: float
    ) -> np.ndarray[Any, Any]:
        """
        Synthesize a simple sine tone modulated by probability (amplitude).
        """
        t = np.linspace(0, duration_ms / 1000, int(self.sample_rate * duration_ms / 1000))
        waveform = probability * np.sin(2 * np.pi * frequency * t)
        return waveform

    def bitstream_to_audio(self, bitstream: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]:
        """
        Roughly convert a bitstream to an audio signal (Filtering).
        """
        # Low-pass filter the bitstream to get 'analog' signal
        # Simplified: moving average
        window = 10
        audio = np.convolve(bitstream, np.ones(window) / window, mode="same")
        return audio

synthesize_tone(frequency, duration_ms, probability)

Synthesize a simple sine tone modulated by probability (amplitude).

Source code in src/sc_neurocore/generative/audio_synthesis.py
22
23
24
25
26
27
28
29
30
def synthesize_tone(
    self, frequency: float, duration_ms: int, probability: float
) -> np.ndarray[Any, Any]:
    """
    Synthesize a simple sine tone modulated by probability (amplitude).
    """
    t = np.linspace(0, duration_ms / 1000, int(self.sample_rate * duration_ms / 1000))
    waveform = probability * np.sin(2 * np.pi * frequency * t)
    return waveform

bitstream_to_audio(bitstream)

Roughly convert a bitstream to an audio signal (Filtering).

Source code in src/sc_neurocore/generative/audio_synthesis.py
32
33
34
35
36
37
38
39
40
def bitstream_to_audio(self, bitstream: np.ndarray[Any, Any]) -> np.ndarray[Any, Any]:
    """
    Roughly convert a bitstream to an audio signal (Filtering).
    """
    # Low-pass filter the bitstream to get 'analog' signal
    # Simplified: moving average
    window = 10
    audio = np.convolve(bitstream, np.ones(window) / window, mode="same")
    return audio

Text Generation

sc_neurocore.generative.text_gen

SCTextGenerator dataclass

A minimal token-level text generator for SC. Maps probability distributions over vocabulary to tokens.

Source code in src/sc_neurocore/generative/text_gen.py
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@dataclass
class SCTextGenerator:
    """
    A minimal token-level text generator for SC.
    Maps probability distributions over vocabulary to tokens.
    """

    vocab: List[str]

    def generate_token(self, prob_dist: np.ndarray[Any, Any]) -> str:
        """
        Input: prob_dist (len(vocab),)
        Returns: selected token based on probability.
        """
        # Ensure it sums to 1
        dist = prob_dist / (np.sum(prob_dist) + 1e-9)
        idx = np.random.choice(len(self.vocab), p=dist)
        return self.vocab[idx]

    def generate_sequence(self, length: int) -> str:
        """
        Generate a random sequence of tokens.
        """
        tokens = [
            self.generate_token(np.random.dirichlet(np.ones(len(self.vocab))))
            for _ in range(length)
        ]
        return " ".join(tokens)

generate_token(prob_dist)

Input: prob_dist (len(vocab),) Returns: selected token based on probability.

Source code in src/sc_neurocore/generative/text_gen.py
23
24
25
26
27
28
29
30
31
def generate_token(self, prob_dist: np.ndarray[Any, Any]) -> str:
    """
    Input: prob_dist (len(vocab),)
    Returns: selected token based on probability.
    """
    # Ensure it sums to 1
    dist = prob_dist / (np.sum(prob_dist) + 1e-9)
    idx = np.random.choice(len(self.vocab), p=dist)
    return self.vocab[idx]

generate_sequence(length)

Generate a random sequence of tokens.

Source code in src/sc_neurocore/generative/text_gen.py
33
34
35
36
37
38
39
40
41
def generate_sequence(self, length: int) -> str:
    """
    Generate a random sequence of tokens.
    """
    tokens = [
        self.generate_token(np.random.dirichlet(np.ones(len(self.vocab))))
        for _ in range(length)
    ]
    return " ".join(tokens)

3D Generation

sc_neurocore.generative.three_d_gen

SC3DGenerator dataclass

Generator for 3D mesh and point cloud outputs from stochastic voxel data.

Implements Marching Cubes algorithm for isosurface extraction.

Source code in src/sc_neurocore/generative/three_d_gen.py
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
@dataclass
class SC3DGenerator:
    """
    Generator for 3D mesh and point cloud outputs from stochastic voxel data.

    Implements Marching Cubes algorithm for isosurface extraction.
    """

    iso_level: float = 0.5  # Threshold for surface extraction

    def export_point_cloud_json(
        self, points: np.ndarray[Any, Any], intensities: np.ndarray[Any, Any], filename: str
    ) -> None:
        """
        Export a point cloud to JSON format.

        Args:
            points: Nx3 array of point coordinates
            intensities: N array of intensity values
            filename: Output file path
        """
        data = {
            "format": "sc_neurocore_pointcloud",
            "version": "1.0",
            "n_points": int(len(points)),
            "points": points.tolist(),
            "intensities": intensities.tolist(),
        }
        with open(filename, "w") as f:
            json.dump(data, f, indent=2)
        logger.info("3D Export: Saved %d points to %s", len(points), filename)

    def generate_surface_mesh(
        self, voxel_grid: np.ndarray[Any, Any], iso_level: Optional[float] = None
    ) -> Dict[str, Any]:
        """
        Generate a surface mesh from a voxel grid using Marching Cubes.

        Args:
            voxel_grid: 3D numpy array of scalar values
            iso_level: Isosurface threshold (default: self.iso_level)

        Returns:
            Dict with 'vertices', 'faces', 'normals'
        """
        if iso_level is None:
            iso_level = self.iso_level

        if voxel_grid.ndim != 3:
            raise ValueError(f"Expected 3D array, got {voxel_grid.ndim}D")

        vertices: list[float] = []
        faces = []

        nx, ny, nz = voxel_grid.shape

        # Process each cube in the grid
        for i in range(nx - 1):
            for j in range(ny - 1):
                for k in range(nz - 1):
                    # Get the 8 corner values
                    cube_vals = [
                        voxel_grid[i, j, k],
                        voxel_grid[i + 1, j, k],
                        voxel_grid[i + 1, j + 1, k],
                        voxel_grid[i, j + 1, k],
                        voxel_grid[i, j, k + 1],
                        voxel_grid[i + 1, j, k + 1],
                        voxel_grid[i + 1, j + 1, k + 1],
                        voxel_grid[i, j + 1, k + 1],
                    ]

                    # Determine cube index
                    cube_index = 0
                    for idx, val in enumerate(cube_vals):
                        if val < iso_level:
                            cube_index |= 1 << idx

                    # Skip if no surface crosses this cube
                    if EDGE_TABLE[cube_index] == 0:
                        continue

                    # Get edge vertices
                    edge_verts = self._get_edge_vertices(i, j, k, cube_vals, iso_level)

                    # Create triangles
                    tri_list = TRI_TABLE[cube_index]
                    for t in range(0, len(tri_list), 3):
                        if t + 2 < len(tri_list):
                            v1_idx = len(vertices)
                            vertices.append(edge_verts[tri_list[t]])  # type: ignore
                            vertices.append(edge_verts[tri_list[t + 1]])  # type: ignore
                            vertices.append(edge_verts[tri_list[t + 2]])  # type: ignore
                            faces.append([v1_idx, v1_idx + 1, v1_idx + 2])

        # Convert to numpy arrays
        vertices = np.array(vertices) if vertices else np.zeros((0, 3))
        faces = np.array(faces, dtype=np.int32) if faces else np.zeros((0, 3), dtype=np.int32)

        # Compute normals
        normals = self._compute_normals(vertices, faces)

        return {
            "vertices": vertices,
            "faces": faces,
            "normals": normals,
            "n_vertices": len(vertices),
            "n_faces": len(faces),
        }

    def _get_edge_vertices(
        self, i: int, j: int, k: int, cube_vals: List[float], iso_level: float
    ) -> Dict[int, np.ndarray[Any, Any]]:
        """Compute vertex positions along cube edges."""
        # Cube corner positions
        corners = np.array(
            [
                [i, j, k],
                [i + 1, j, k],
                [i + 1, j + 1, k],
                [i, j + 1, k],
                [i, j, k + 1],
                [i + 1, j, k + 1],
                [i + 1, j + 1, k + 1],
                [i, j + 1, k + 1],
            ],
            dtype=np.float64,
        )

        # Edge endpoints
        edges = [
            (0, 1),
            (1, 2),
            (2, 3),
            (3, 0),
            (4, 5),
            (5, 6),
            (6, 7),
            (7, 4),
            (0, 4),
            (1, 5),
            (2, 6),
            (3, 7),
        ]

        edge_verts = {}
        for edge_idx, (v0, v1) in enumerate(edges):
            if cube_vals[v0] != cube_vals[v1]:
                # Linear interpolation
                t = (iso_level - cube_vals[v0]) / (cube_vals[v1] - cube_vals[v0])
                t = np.clip(t, 0, 1)
                edge_verts[edge_idx] = corners[v0] + t * (corners[v1] - corners[v0])
            else:
                edge_verts[edge_idx] = (corners[v0] + corners[v1]) / 2

        return edge_verts

    def _compute_normals(
        self, vertices: np.ndarray[Any, Any], faces: np.ndarray[Any, Any]
    ) -> np.ndarray[Any, Any]:
        """Compute vertex normals from face normals."""
        if len(vertices) == 0 or len(faces) == 0:
            return np.zeros((0, 3))

        # Initialize vertex normals
        normals = np.zeros_like(vertices)

        # Compute face normals and accumulate to vertices
        for face in faces:
            v0, v1, v2 = vertices[face[0]], vertices[face[1]], vertices[face[2]]
            edge1 = v1 - v0
            edge2 = v2 - v0
            face_normal = np.cross(edge1, edge2)
            norm = np.linalg.norm(face_normal)
            if norm > 1e-8:
                face_normal /= norm
            for vi in face:
                normals[vi] += face_normal

        # Normalize vertex normals
        norms = np.linalg.norm(normals, axis=1, keepdims=True)
        norms = np.where(norms > 1e-8, norms, 1.0)
        normals /= norms

        return normals

    def export_mesh_obj(self, mesh: Dict[str, Any], filename: str) -> None:
        """
        Export mesh to OBJ format.

        Args:
            mesh: Dict from generate_surface_mesh()
            filename: Output file path
        """
        vertices = mesh["vertices"]
        faces = mesh["faces"]
        normals = mesh.get("normals", np.zeros_like(vertices))

        with open(filename, "w") as f:
            f.write("# SC-NeuroCore Generated Mesh\n")
            f.write(f"# Vertices: {len(vertices)}, Faces: {len(faces)}\n\n")

            # Write vertices
            for v in vertices:
                f.write(f"v {v[0]:.6f} {v[1]:.6f} {v[2]:.6f}\n")

            # Write normals
            for n in normals:
                f.write(f"vn {n[0]:.6f} {n[1]:.6f} {n[2]:.6f}\n")

            # Write faces (OBJ uses 1-based indexing)
            for face in faces:
                f.write(
                    f"f {face[0] + 1}//{face[0] + 1} "
                    f"{face[1] + 1}//{face[1] + 1} "
                    f"{face[2] + 1}//{face[2] + 1}\n"
                )

        logger.info("3D Export: Saved mesh to %s", filename)

    def export_mesh_json(self, mesh: Dict[str, Any], filename: str) -> None:
        """
        Export mesh to JSON format.

        Args:
            mesh: Dict from generate_surface_mesh()
            filename: Output file path
        """
        data = {
            "format": "sc_neurocore_mesh",
            "version": "1.0",
            "n_vertices": int(mesh["n_vertices"]),
            "n_faces": int(mesh["n_faces"]),
            "vertices": mesh["vertices"].tolist(),
            "faces": mesh["faces"].tolist(),
            "normals": mesh["normals"].tolist(),
        }
        with open(filename, "w") as f:
            json.dump(data, f)
        logger.info("3D Export: Saved mesh JSON to %s", filename)

    def bitstream_to_voxels(
        self, bitstreams: np.ndarray[Any, Any], grid_size: Tuple[int, int, int] = (16, 16, 16)
    ) -> np.ndarray[Any, Any]:
        """
        Convert bitstream outputs to a voxel grid.

        Args:
            bitstreams: 2D array of bitstreams (n_units, length)
            grid_size: Output voxel grid dimensions

        Returns:
            3D voxel grid with probability-based values
        """
        n_voxels = np.prod(grid_size)
        n_units = len(bitstreams)

        # Compute probabilities from bitstreams
        probs = np.mean(bitstreams, axis=1)

        # Resize/reshape to fill grid
        if n_units >= n_voxels:
            # Subsample
            indices = np.linspace(0, n_units - 1, n_voxels, dtype=int)
            voxel_values = probs[indices]
        else:
            # Interpolate
            x_old = np.linspace(0, 1, n_units)
            x_new = np.linspace(0, 1, n_voxels)
            voxel_values = np.interp(x_new, x_old, probs)

        return voxel_values.reshape(grid_size)

    def generate_from_scpn(
        self, scpn_outputs: Dict[str, Any], grid_size: Tuple[int, int, int] = (16, 16, 16)
    ) -> Dict[str, Any]:
        """
        Generate 3D mesh directly from SCPN layer outputs.

        Args:
            scpn_outputs: Output from run_integrated_step()
            grid_size: Voxel grid dimensions

        Returns:
            Mesh dict from generate_surface_mesh()
        """
        # Collect all bitstreams from SCPN layers
        all_bitstreams = []
        for layer_name, output in scpn_outputs.items():
            if isinstance(output, dict) and "output_bitstreams" in output:
                bs = output["output_bitstreams"]
                if bs is not None and len(bs) > 0:
                    all_bitstreams.append(bs)

        if not all_bitstreams:
            # Return empty mesh
            return {
                "vertices": np.zeros((0, 3)),
                "faces": np.zeros((0, 3), dtype=np.int32),
                "normals": np.zeros((0, 3)),
                "n_vertices": 0,
                "n_faces": 0,
            }

        # Combine bitstreams
        combined = np.vstack(all_bitstreams)

        # Convert to voxels
        voxels = self.bitstream_to_voxels(combined, grid_size)

        # Generate mesh
        return self.generate_surface_mesh(voxels)

export_point_cloud_json(points, intensities, filename)

Export a point cloud to JSON format.

Parameters:

Name Type Description Default
points ndarray[Any, Any]

Nx3 array of point coordinates

required
intensities ndarray[Any, Any]

N array of intensity values

required
filename str

Output file path

required
Source code in src/sc_neurocore/generative/three_d_gen.py
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
def export_point_cloud_json(
    self, points: np.ndarray[Any, Any], intensities: np.ndarray[Any, Any], filename: str
) -> None:
    """
    Export a point cloud to JSON format.

    Args:
        points: Nx3 array of point coordinates
        intensities: N array of intensity values
        filename: Output file path
    """
    data = {
        "format": "sc_neurocore_pointcloud",
        "version": "1.0",
        "n_points": int(len(points)),
        "points": points.tolist(),
        "intensities": intensities.tolist(),
    }
    with open(filename, "w") as f:
        json.dump(data, f, indent=2)
    logger.info("3D Export: Saved %d points to %s", len(points), filename)

generate_surface_mesh(voxel_grid, iso_level=None)

Generate a surface mesh from a voxel grid using Marching Cubes.

Parameters:

Name Type Description Default
voxel_grid ndarray[Any, Any]

3D numpy array of scalar values

required
iso_level Optional[float]

Isosurface threshold (default: self.iso_level)

None

Returns:

Type Description
Dict[str, Any]

Dict with 'vertices', 'faces', 'normals'

Source code in src/sc_neurocore/generative/three_d_gen.py
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
def generate_surface_mesh(
    self, voxel_grid: np.ndarray[Any, Any], iso_level: Optional[float] = None
) -> Dict[str, Any]:
    """
    Generate a surface mesh from a voxel grid using Marching Cubes.

    Args:
        voxel_grid: 3D numpy array of scalar values
        iso_level: Isosurface threshold (default: self.iso_level)

    Returns:
        Dict with 'vertices', 'faces', 'normals'
    """
    if iso_level is None:
        iso_level = self.iso_level

    if voxel_grid.ndim != 3:
        raise ValueError(f"Expected 3D array, got {voxel_grid.ndim}D")

    vertices: list[float] = []
    faces = []

    nx, ny, nz = voxel_grid.shape

    # Process each cube in the grid
    for i in range(nx - 1):
        for j in range(ny - 1):
            for k in range(nz - 1):
                # Get the 8 corner values
                cube_vals = [
                    voxel_grid[i, j, k],
                    voxel_grid[i + 1, j, k],
                    voxel_grid[i + 1, j + 1, k],
                    voxel_grid[i, j + 1, k],
                    voxel_grid[i, j, k + 1],
                    voxel_grid[i + 1, j, k + 1],
                    voxel_grid[i + 1, j + 1, k + 1],
                    voxel_grid[i, j + 1, k + 1],
                ]

                # Determine cube index
                cube_index = 0
                for idx, val in enumerate(cube_vals):
                    if val < iso_level:
                        cube_index |= 1 << idx

                # Skip if no surface crosses this cube
                if EDGE_TABLE[cube_index] == 0:
                    continue

                # Get edge vertices
                edge_verts = self._get_edge_vertices(i, j, k, cube_vals, iso_level)

                # Create triangles
                tri_list = TRI_TABLE[cube_index]
                for t in range(0, len(tri_list), 3):
                    if t + 2 < len(tri_list):
                        v1_idx = len(vertices)
                        vertices.append(edge_verts[tri_list[t]])  # type: ignore
                        vertices.append(edge_verts[tri_list[t + 1]])  # type: ignore
                        vertices.append(edge_verts[tri_list[t + 2]])  # type: ignore
                        faces.append([v1_idx, v1_idx + 1, v1_idx + 2])

    # Convert to numpy arrays
    vertices = np.array(vertices) if vertices else np.zeros((0, 3))
    faces = np.array(faces, dtype=np.int32) if faces else np.zeros((0, 3), dtype=np.int32)

    # Compute normals
    normals = self._compute_normals(vertices, faces)

    return {
        "vertices": vertices,
        "faces": faces,
        "normals": normals,
        "n_vertices": len(vertices),
        "n_faces": len(faces),
    }

export_mesh_obj(mesh, filename)

Export mesh to OBJ format.

Parameters:

Name Type Description Default
mesh Dict[str, Any]

Dict from generate_surface_mesh()

required
filename str

Output file path

required
Source code in src/sc_neurocore/generative/three_d_gen.py
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
def export_mesh_obj(self, mesh: Dict[str, Any], filename: str) -> None:
    """
    Export mesh to OBJ format.

    Args:
        mesh: Dict from generate_surface_mesh()
        filename: Output file path
    """
    vertices = mesh["vertices"]
    faces = mesh["faces"]
    normals = mesh.get("normals", np.zeros_like(vertices))

    with open(filename, "w") as f:
        f.write("# SC-NeuroCore Generated Mesh\n")
        f.write(f"# Vertices: {len(vertices)}, Faces: {len(faces)}\n\n")

        # Write vertices
        for v in vertices:
            f.write(f"v {v[0]:.6f} {v[1]:.6f} {v[2]:.6f}\n")

        # Write normals
        for n in normals:
            f.write(f"vn {n[0]:.6f} {n[1]:.6f} {n[2]:.6f}\n")

        # Write faces (OBJ uses 1-based indexing)
        for face in faces:
            f.write(
                f"f {face[0] + 1}//{face[0] + 1} "
                f"{face[1] + 1}//{face[1] + 1} "
                f"{face[2] + 1}//{face[2] + 1}\n"
            )

    logger.info("3D Export: Saved mesh to %s", filename)

export_mesh_json(mesh, filename)

Export mesh to JSON format.

Parameters:

Name Type Description Default
mesh Dict[str, Any]

Dict from generate_surface_mesh()

required
filename str

Output file path

required
Source code in src/sc_neurocore/generative/three_d_gen.py
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
def export_mesh_json(self, mesh: Dict[str, Any], filename: str) -> None:
    """
    Export mesh to JSON format.

    Args:
        mesh: Dict from generate_surface_mesh()
        filename: Output file path
    """
    data = {
        "format": "sc_neurocore_mesh",
        "version": "1.0",
        "n_vertices": int(mesh["n_vertices"]),
        "n_faces": int(mesh["n_faces"]),
        "vertices": mesh["vertices"].tolist(),
        "faces": mesh["faces"].tolist(),
        "normals": mesh["normals"].tolist(),
    }
    with open(filename, "w") as f:
        json.dump(data, f)
    logger.info("3D Export: Saved mesh JSON to %s", filename)

bitstream_to_voxels(bitstreams, grid_size=(16, 16, 16))

Convert bitstream outputs to a voxel grid.

Parameters:

Name Type Description Default
bitstreams ndarray[Any, Any]

2D array of bitstreams (n_units, length)

required
grid_size Tuple[int, int, int]

Output voxel grid dimensions

(16, 16, 16)

Returns:

Type Description
ndarray[Any, Any]

3D voxel grid with probability-based values

Source code in src/sc_neurocore/generative/three_d_gen.py
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
def bitstream_to_voxels(
    self, bitstreams: np.ndarray[Any, Any], grid_size: Tuple[int, int, int] = (16, 16, 16)
) -> np.ndarray[Any, Any]:
    """
    Convert bitstream outputs to a voxel grid.

    Args:
        bitstreams: 2D array of bitstreams (n_units, length)
        grid_size: Output voxel grid dimensions

    Returns:
        3D voxel grid with probability-based values
    """
    n_voxels = np.prod(grid_size)
    n_units = len(bitstreams)

    # Compute probabilities from bitstreams
    probs = np.mean(bitstreams, axis=1)

    # Resize/reshape to fill grid
    if n_units >= n_voxels:
        # Subsample
        indices = np.linspace(0, n_units - 1, n_voxels, dtype=int)
        voxel_values = probs[indices]
    else:
        # Interpolate
        x_old = np.linspace(0, 1, n_units)
        x_new = np.linspace(0, 1, n_voxels)
        voxel_values = np.interp(x_new, x_old, probs)

    return voxel_values.reshape(grid_size)

generate_from_scpn(scpn_outputs, grid_size=(16, 16, 16))

Generate 3D mesh directly from SCPN layer outputs.

Parameters:

Name Type Description Default
scpn_outputs Dict[str, Any]

Output from run_integrated_step()

required
grid_size Tuple[int, int, int]

Voxel grid dimensions

(16, 16, 16)

Returns:

Type Description
Dict[str, Any]

Mesh dict from generate_surface_mesh()

Source code in src/sc_neurocore/generative/three_d_gen.py
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
def generate_from_scpn(
    self, scpn_outputs: Dict[str, Any], grid_size: Tuple[int, int, int] = (16, 16, 16)
) -> Dict[str, Any]:
    """
    Generate 3D mesh directly from SCPN layer outputs.

    Args:
        scpn_outputs: Output from run_integrated_step()
        grid_size: Voxel grid dimensions

    Returns:
        Mesh dict from generate_surface_mesh()
    """
    # Collect all bitstreams from SCPN layers
    all_bitstreams = []
    for layer_name, output in scpn_outputs.items():
        if isinstance(output, dict) and "output_bitstreams" in output:
            bs = output["output_bitstreams"]
            if bs is not None and len(bs) > 0:
                all_bitstreams.append(bs)

    if not all_bitstreams:
        # Return empty mesh
        return {
            "vertices": np.zeros((0, 3)),
            "faces": np.zeros((0, 3), dtype=np.int32),
            "normals": np.zeros((0, 3)),
            "n_vertices": 0,
            "n_faces": 0,
        }

    # Combine bitstreams
    combined = np.vstack(all_bitstreams)

    # Convert to voxels
    voxels = self.bitstream_to_voxels(combined, grid_size)

    # Generate mesh
    return self.generate_surface_mesh(voxels)