Source code for analytic_continuation_server.routes.meromorphic

"""
Meromorphic function building API endpoints.

Provides routes for:
- Building meromorphic expressions from zeros and poles
- Combined meromorphic + domain coloring generation
"""

from typing import Optional, Tuple
from fastapi import APIRouter

from analytic_continuation import (
    SpaceAdapter,
    Singularity,
    build_meromorphic_expression,
)

from ..models import (
    MeromorphicRequest,
    MeromorphicResponse,
    SingularityModel,
    DomainColorRequest,
)
from ..converters import params_model_to_params

router = APIRouter(prefix="/api/meromorphic", tags=["meromorphic"])


[docs] @router.post("/build") async def build_meromorphic(request: MeromorphicRequest) -> MeromorphicResponse: """ Build a meromorphic function expression from zeros and poles. Accepts points in either screen or logical coordinates. Returns the sympy-compatible expression and points in logical coords. Example request: { "zeros": [{"x": 1, "y": 0}, {"x": -1, "y": 0}], "poles": [{"x": 0, "y": 1}, {"x": 0, "y": -1}], "coords": "logical" } Returns: { "expression": "(z-1)*(z+1)/((z-i)*(z+i))", "zeros": [...], "poles": [...] } """ # Transform to logical coordinates if needed if request.coords == "screen" and request.params: adapter = SpaceAdapter(params_model_to_params(request.params)) logical_zeros = [] for z in request.zeros: lx, ly = adapter.screen_to_logical(z.x, z.y) logical_zeros.append(SingularityModel(x=lx, y=ly, multiplicity=z.multiplicity)) logical_poles = [] for p in request.poles: lx, ly = adapter.screen_to_logical(p.x, p.y) logical_poles.append(SingularityModel(x=lx, y=ly, multiplicity=p.multiplicity)) else: logical_zeros = request.zeros logical_poles = request.poles # Convert to Singularity objects and build expression zero_sings = [Singularity(z.x, z.y, z.multiplicity) for z in logical_zeros] pole_sings = [Singularity(p.x, p.y, p.multiplicity) for p in logical_poles] expression = build_meromorphic_expression(zero_sings, pole_sings) return MeromorphicResponse( expression=expression, zeros=logical_zeros, poles=logical_poles, )
[docs] @router.post("/domaincolor") async def meromorphic_domain_color( request: MeromorphicRequest, x_range: Tuple[float, float] = (-2.0, 2.0), y_range: Optional[Tuple[float, float]] = None, resolution: int = 800, ): """ Build a meromorphic function from zeros/poles and generate domain coloring. Combines /api/meromorphic/build and /api/domaincolor into one call. """ # Import here to avoid circular imports from .domaincolor import generate_domain_color # First build the expression build_response = await build_meromorphic(request) # Then generate the domain coloring dc_request = DomainColorRequest( expression=build_response.expression, x_range=x_range, y_range=y_range, resolution=resolution, ) return await generate_domain_color(dc_request)