Download scoobdoob/mb_potential.py from ChatterjeeLab/ScooBDoob: direct link, hf CLI and curl.
- Browser
- Download file 3.48 kB
-
https://huggingface.co/ChatterjeeLab/ScooBDoob/resolve/main/scoobdoob/mb_potential.py
- Command line
-
hf download hf://ChatterjeeLab/ScooBDoob/scoobdoob/mb_potential.py
-
curl -L -o mb_potential.py https://huggingface.co/ChatterjeeLab/ScooBDoob/resolve/main/scoobdoob/mb_potential.py
3.48 kB
| import numpy as np | |
| import torch | |
| def _to_torch_dtype(dt): | |
| if isinstance(dt, torch.dtype) or dt is None: | |
| return dt or torch.get_default_dtype() | |
| mapping = { | |
| np.dtype("float32"): torch.float32, | |
| np.float32: torch.float32, | |
| np.dtype("float64"): torch.float64, | |
| np.float64: torch.float64, | |
| np.dtype("int32"): torch.int32, | |
| np.int32: torch.int32, | |
| np.dtype("int64"): torch.int64, | |
| np.int64: torch.int64, | |
| } | |
| return mapping.get(dt, torch.get_default_dtype()) | |
| def mb_params(device=None, dtype=torch.float32): | |
| dtype = _to_torch_dtype(dtype) | |
| A = torch.tensor([-200.0, -100.0, -170.0, 15.0], device=device, dtype=dtype) | |
| a = torch.tensor([-1.0, -1.0, -6.5, 0.7], device=device, dtype=dtype) | |
| b = torch.tensor([0.0, 0.0, 11.0, 0.6], device=device, dtype=dtype) | |
| c = torch.tensor([-10.0, -10.0, -6.5, 0.7], device=device, dtype=dtype) | |
| x0 = torch.tensor([1.0, 0.0, -0.5, -1.0], device=device, dtype=dtype) | |
| y0 = torch.tensor([0.0, 0.5, 1.5, 1.0], device=device, dtype=dtype) | |
| return A, a, b, c, x0, y0 | |
| def mb_potential_xy(x, y): | |
| """Compute Müller-Brown potential U(x,y). Args: x, y: torch tensors (broadcastable to same shape) Returns: U: torch tensor, same broadcasted shape""" | |
| device = ( | |
| x.device | |
| if isinstance(x, torch.Tensor) | |
| else (y.device if isinstance(y, torch.Tensor) else None) | |
| ) | |
| dt = ( | |
| x.dtype | |
| if isinstance(x, torch.Tensor) | |
| else (y.dtype if isinstance(y, torch.Tensor) else None) | |
| ) | |
| dt = _to_torch_dtype(dt) | |
| x = torch.as_tensor(x, dtype=dt, device=device) | |
| y = torch.as_tensor(y, dtype=dt, device=device) | |
| A, a, b, c, x0, y0 = mb_params(device=x.device, dtype=dt) | |
| X = x[..., None] | |
| Y = y[..., None] | |
| exp_arg = a * (X - x0) ** 2 + b * (X - x0) * (Y - y0) + c * (Y - y0) ** 2 | |
| U = torch.sum(A * torch.exp(exp_arg), dim=-1) | |
| return U | |
| def mb_grad_xy(x, y): | |
| """ | |
| Gradient of U: returns (dU/dx, dU/dy) | |
| """ | |
| device, dtype = x.device, x.dtype | |
| A, a, b, c, x0, y0 = mb_params(device=device, dtype=dtype) | |
| X = x[..., None] | |
| Y = y[..., None] | |
| dx = X - x0 | |
| dy = Y - y0 | |
| exp_arg = a * dx * dx + b * dx * dy + c * dy * dy | |
| E = torch.exp(exp_arg) * A | |
| dUdx = torch.sum(E * (2 * a * dx + b * dy), dim=-1) | |
| dUdy = torch.sum(E * (b * dx + 2 * c * dy), dim=-1) | |
| return dUdx, dUdy | |
| def simulate_overdamped_mb( | |
| n_steps=100000, | |
| dt=1e-3, | |
| beta=1.0, | |
| mu=1.0, | |
| x0=None, | |
| y0=None, | |
| noise=True, | |
| device="cpu", | |
| dtype=torch.float32, | |
| seed=None, | |
| ): | |
| """ | |
| Generate unconditioned trajectories on the MB surface. | |
| Overdamped Langevin: dx = -mu * grad U dt + sqrt(2 mu / beta) dW | |
| Returns numpy arrays (xs, ys) of shape [n_steps]. | |
| A sequence of coordinates with a fixed dt | |
| """ | |
| if seed is not None: | |
| torch.manual_seed(seed) | |
| np.random.seed(seed) | |
| x = torch.tensor([x0], device=device, dtype=dtype) | |
| y = torch.tensor([y0], device=device, dtype=dtype) | |
| xs = torch.empty(n_steps, dtype=dtype, device=device) | |
| ys = torch.empty(n_steps, dtype=dtype, device=device) | |
| sigma = (2.0 * mu / beta * dt) ** 0.5 | |
| for t in range(n_steps): | |
| dUdx, dUdy = mb_grad_xy(x, y) | |
| x = x - mu * dUdx * dt + sigma * torch.randn_like(x) | |
| y = y - mu * dUdy * dt + sigma * torch.randn_like(y) | |
| xs[t] = x | |
| ys[t] = y | |
| return xs.cpu().numpy(), ys.cpu().numpy() | |