### Install Latest Development Version Source: https://hugomvale.github.io/odrpack-python Install the most recent code directly from the GitHub repository. This version may be unstable and is not recommended for production use. ```bash pip install git+https://github.com/HugoMVale/odrpack-python.git ``` -------------------------------- ### odr_fit Example with Bounds Source: https://hugomvale.github.io/odrpack-python/reference Demonstrates how to use odr_fit to perform regression with specified bounds on the parameters. This is useful when the model parameters have known constraints. ```python import numpy as np from odrpack import odr_fit xdata = [0.982, 1.998, 4.978, 6.01] ydata = [2.7, 7.4, 148.0, 403.0] beta0 = [2., 0.5] bounds = ([0., 0.], [10., 0.9]) def f(x: np.ndarray, beta: np.ndarray) -> np.ndarray: return beta[0] * np.exp(beta[1]*x) sol = odr_fit(f, xdata, ydata, beta0, bounds=bounds) sol.beta array([1.63336897, 0.9 ]) ``` -------------------------------- ### Install Latest Stable Version Source: https://hugomvale.github.io/odrpack-python Use this command to install the latest stable release of odrpack from the Python Package Index (PyPI). Ensure you have Python 3.10 or newer and numpy installed. ```bash pip install odrpack ``` -------------------------------- ### Get Work Array Indices Source: https://hugomvale.github.io/odrpack-python/reference Retrieves dictionaries containing the starting indices for various quantities within the 'iwork' and 'rwork' arrays. These are essential for correctly extracting results from the work arrays after the ODRPACK routine has run. ```python # Indexes of integer and real work arrays iwork_idx: dict[str, int] = loc_iwork(m, q, npar) rwork_idx: dict[str, int] = loc_rwork(n, m, q, npar, ldwe, ld2we, is_odr) ``` -------------------------------- ### Check regression convergence and parameters Source: https://hugomvale.github.io/odrpack-python/examples/explicit-model Inspect the 'stopreason' attribute to verify convergence and access the estimated model parameters via the 'beta' attribute of the solution object. ```python sol.stopreason ``` ```python sol.beta ``` -------------------------------- ### Define initial guess and bounds for parameters Source: https://hugomvale.github.io/odrpack-python/examples/explicit-model Set an initial guess for the model parameters (beta0) and define the lower and upper bounds for each parameter. This helps in constraining the optimization process. ```python beta0 = [1.0, 1.0] lower = [0.0, 0.0] upper = [2.0, 2.0] ``` -------------------------------- ### Import necessary libraries Source: https://hugomvale.github.io/odrpack-python/examples/implicit-model Import matplotlib for plotting, numpy for numerical operations, Ellipse from matplotlib.patches for drawing ellipses, and odr_fit from odrpack for orthogonal distance regression. ```python import matplotlib.pyplot as plt import numpy as np from matplotlib.patches import Ellipse from odrpack import odr_fit ``` -------------------------------- ### Initialize Job Flag Source: https://hugomvale.github.io/odrpack-python/reference Initializes the `jobl` flag, which is an array of five integers used to control the ODRPACK solver's behavior. The initial state is all zeros. ```python # Set job flag jobl = [0, 0, 0, 0, 0] ``` -------------------------------- ### Set initial guess and bounds for parameters Source: https://hugomvale.github.io/odrpack-python/examples/implicit-model Define the initial guess (beta0) for the ellipse parameters (center x0, y0, semi-axes a, b, and rotation angle theta). Also, define the lower and upper bounds for each parameter to constrain the search space during regression. ```python beta0 = [0.0, 0.0, 1.0, 1.0, 0.0] lower = [-1e2, -1e2, 0e0, 0e0, -np.pi/2] upper = [+1e2, +1e2, 1e2, 1e2, +np.pi/2] ``` -------------------------------- ### Configure ODRPACK Job Parameters Source: https://hugomvale.github.io/odrpack-python/reference This code block sets up the 'job' parameter based on the specified task, derivative scheme, and whether Jacobians or delta0 are provided. It prepares the integer array 'jobl' which is then converted into a single integer 'job'. ```python if task == "explicit-ODR": jobl[-1] = 0 is_odr = True elif task == "implicit-ODR": jobl[-1] = 1 is_odr = True elif task == "OLS": jobl[-1] = 2 is_odr = False else: raise ValueError( f"Invalid value for `task`: {task}.") if has_jac: jobl[-2] = 2 else: if diff_scheme == "forward": jobl[-2] = 0 elif diff_scheme == "central": jobl[-2] = 1 else: raise ValueError( f"Invalid value for `diff_scheme`: {diff_scheme}.") if has_delta0: jobl[-4] = 1 job = sum(jobl[i] * 10 ** (len(jobl) - 1 - i) for i in range(len(jobl))) ``` -------------------------------- ### Allocate and Initialize Work Arrays Source: https://hugomvale.github.io/odrpack-python/reference This snippet allocates the necessary real and integer work arrays ('rwork', 'iwork') based on dimensions calculated by 'workspace_dimensions'. It initializes these arrays with zeros. ```python # Allocate work arrays (drop restart possibility) lrwork, liwork = workspace_dimensions(n, m, q, npar, is_odr) rwork = np.zeros(lrwork, dtype=np.float64) iwork = np.zeros(liwork, dtype=np.int32) ``` -------------------------------- ### Display estimated parameters Source: https://hugomvale.github.io/odrpack-python/examples/implicit-model Access and display the 'beta' attribute of the solution object, which contains the estimated parameters (x0, y0, a, b, theta) of the fitted ellipse. ```python sol.beta ``` -------------------------------- ### Import necessary libraries Source: https://hugomvale.github.io/odrpack-python/examples/explicit-model Import matplotlib for plotting, numpy for numerical operations, and odr_fit from the odrpack library. ```python import matplotlib.pyplot as plt import numpy as np from odrpack import odr_fit ``` -------------------------------- ### Check convergence reason Source: https://hugomvale.github.io/odrpack-python/examples/implicit-model Inspect the 'stopreason' attribute of the solution object to verify if the regression algorithm converged successfully. ```python sol.stopreason ``` -------------------------------- ### Map Report String to Iprint Flag Source: https://hugomvale.github.io/odrpack-python/reference Translates the user-friendly `report` string ('none', 'short', 'long', 'iteration') into the corresponding integer `iprint` flag used internally. ```python # Set iprint flag iprint_mapping = { 'none': 0, 'short': 1001, 'long': 2002, 'iteration': 2212 } iprint = iprint_mapping[report] ``` -------------------------------- ### Plot experimental data and fitted model Source: https://hugomvale.github.io/odrpack-python/examples/explicit-model Visualize the experimental data points and the fitted non-linear model curve using matplotlib. This helps in assessing the quality of the fit. ```python _, ax = plt.subplots() # Plot experimental data ax.plot(xdata, ydata, 'o') # Plot fitted model xm = np.linspace(0.0, 1.0, 100) ym = f(xm, sol.beta) ax.plot(xm, ym) ax.set_xlabel('x') ax.set_ylabel('y'); ``` -------------------------------- ### Convert Fix Parameters to Integer Format Source: https://hugomvale.github.io/odrpack-python/reference Converts boolean arrays 'fix_beta' and 'fix_x' into integer arrays 'ifixb' and 'ifixx' respectively. A value of 1 indicates a fixed parameter, and 0 indicates a free parameter. If the input is None, the output is also None. ```python # Convert fix to ifix ifixb = (~fix_beta).astype(np.int32) if fix_beta is not None else None ifixx = (~fix_x).astype(np.int32) if fix_x is not None else None ``` -------------------------------- ### odr_fit Function Parameters Source: https://hugomvale.github.io/odrpack-python/reference Detailed documentation for the parameters of the odr_fit function. ```APIDOC ## odr_fit ### Parameters - **weight_y** (float | F64ArrayLike | None) - Optional - Specifies how errors on `ydata` are weighted. Can be a scalar, a 1D array for individual point weights, or a matrix representing the covariant weighting matrix. Defaults to one for all data points. - **bounds** (tuple[F64ArrayLike | None, F64ArrayLike | None] | None) - Optional - A tuple containing lower and upper bounds for model parameters, with the same shape as `beta0`. Defaults to negative and positive infinity. - **task** (Literal['explicit-ODR', 'implicit-ODR', 'OLS'] | None) - Optional - Specifies the regression task: 'explicit-ODR' for explicit models, 'implicit-ODR' for implicit models, or 'OLS' for ordinary least squares. Defaults to 'explicit-ODR'. - **fix_beta** (BoolArrayLike | None) - Optional - An array with the same shape as `beta0` to fix specific model parameters. `True` fixes a parameter, `False` allows adjustment. Defaults to all `False`. - **fix_x** (BoolArrayLike | None) - Optional - An array with the same shape as `xdata` to fix specific explanatory variable elements. Can be broadcastable. Defaults to all `False` in ODR mode; `xdata` is always fixed in OLS mode. - **jac_beta** (Callable[[F64Array, F64Array], F64Array] | None) - Optional - The Jacobian of the function with respect to `beta`. Must return an array with shape `(q, npar, n)` or compatible. Defaults to numerical approximation. - **jac_x** (Callable[[F64Array, F64Array], F64Array] | None) - Optional - The Jacobian of the function with respect to `x`. Must return an array with shape `(q, m, n)` or compatible. Defaults to numerical approximation. - **delta0** (F64ArrayLike | None) - Optional - Initial guesses for the errors in the explanatory variable, with the same shape as `xdata`. Defaults to zero. - **diff_scheme** (Literal['forward', 'central'] | None) - Optional - The finite difference scheme for Jacobian approximation. Options are 'forward' or 'central'. Defaults to 'forward'. - **report** (Literal['none', 'short', 'long', 'iteration'] | None) - Optional - Controls the level of reporting during fitting. Options range from 'none' to 'iteration'. Defaults to 'none'. - **maxit** (int | None) - Optional - The maximum number of iterations allowed for the fitting process. Defaults to 50. - **ndigit** (int | None) - Optional - The number of reliable decimal digits in computed values. Defaults to a numerically determined value. ``` -------------------------------- ### Handle Jacobian Availability Source: https://hugomvale.github.io/odrpack-python/reference Sets up the `has_jac` flag and assigns dummy functions if Jacobians are not provided, ensuring consistent behavior. Handles specific cases for `task == 'OLS'`. ```python def fdummy(x, beta): return np.array([np.nan]) # will never be called if jac_beta is None and jac_x is None: has_jac = False jac_beta = fdummy jac_x = fdummy elif jac_beta is not None and jac_x is not None: has_jac = True elif jac_beta is not None and jac_x is None and task == 'OLS': has_jac = False jac_x = fdummy else: raise ValueError("Inconsistent arguments for `jac_beta` and `jac_x`.") ``` -------------------------------- ### Validate weight_x Input Source: https://hugomvale.github.io/odrpack-python/reference Validates the shape of the weight_x parameter, ensuring it matches expected dimensions for diagonal or full matrices. Raises a ValueError for incompatible shapes. ```python # Check weight_x if weight_x is not None: weight_x = np.asarray(weight_x, dtype=np.float64) if weight_x.shape == (): ldwd = 1 ld2wd = 1 weight_x = np.full((m,), weight_x, dtype=np.float64) elif weight_x.shape == (m,): ldwd = 1 ld2wd = 1 elif weight_x.shape == (m, m): ldwd = 1 ld2wd = m elif weight_x.shape == (m, n) or (weight_x.shape == (n,) and m == 1): ldwd = n ld2wd = 1 elif weight_x.shape in ((m, 1, 1), (m, 1, n), (m, m, 1), (m, m, n)): ldwd = weight_x.shape[2] ld2wd = weight_x.shape[1] else: raise ValueError( r"`weight_x` must be a array of shape `(m,)`, `(n,)`, `(m, m)`, `(m, n)`, `(m, 1, 1)`, `(m, 1, n)`, `(m, m, 1)`, or `(m, m, n)`. See page 26 of the ODRPACK95 User Guide.") else: ldwd = 1 ld2wd = 1 ``` -------------------------------- ### Validate parameter bounds for odr_fit Source: https://hugomvale.github.io/odrpack-python/reference Checks the provided bounds for parameters, ensuring they are compatible with beta0's shape and do not violate initial constraints. Raises ValueError for invalid bounds. ```python # Check p bounds if bounds is not None: lower, upper = bounds if lower is not None: lower = np.asarray(lower, dtype=np.float64) if lower.shape != beta0.shape: raise ValueError( "The lower bound `bounds[0]` must have the same shape as `beta0`.") if np.any(lower > beta0): raise ValueError( "The lower bound `bounds[0]` must be less or equal than `beta0`.") if upper is not None: upper = np.asarray(upper, dtype=np.float64) if upper.shape != beta0.shape: raise ValueError( "The upper bound `bounds[1]` must have the same shape as `beta0`.") if np.any(upper < beta0): raise ValueError( "The upper bound `bounds[1]` must be greater or equal than `beta0`.") else: lower, upper = None, None ``` -------------------------------- ### Define experimental data Source: https://hugomvale.github.io/odrpack-python/examples/explicit-model Define the x and y data points for the experiment. These arrays will be used as input for the regression. ```python xdata = [0.100, 0.300, 0.400, 0.500, 0.600, 0.700, 0.800] ydata = [0.059, 0.243, 0.364, 0.486, 0.583, 0.721, 0.824] ``` -------------------------------- ### Define weights for x and y data Source: https://hugomvale.github.io/odrpack-python/examples/explicit-model Calculate the weights for x and y data based on their estimated uncertainties (sigma_x, sigma_y). Higher uncertainty leads to lower weight. ```python sigma_x = 0.01 sigma_y = 0.05 weight_x = 1/sigma_x**2 weight_y = 1/sigma_y**2 ``` -------------------------------- ### Plot observed data and fitted ellipse Source: https://hugomvale.github.io/odrpack-python/examples/implicit-model Visualize the results by plotting the original observed data points and the fitted ellipse. The ellipse is drawn using the estimated parameters (center, semi-axes, and rotation angle). ```python fig, ax = plt.subplots() # Plot observed data ax.plot(*Xdata, 'o') # Plot fitted ellipse x0, y0, a, b, theta = sol.beta ellipse = Ellipse((x0, y0), width=2*a, height=2*b, angle=np.degrees(theta), facecolor='none', edgecolor='orange', linewidth=2) ax.add_patch(ellipse) ax.set_xlabel('x') ax.set_ylabel('y'); ``` -------------------------------- ### Return ODR Fit Result Source: https://hugomvale.github.io/odrpack-python/reference Returns the constructed 'OdrResult' object containing all the outputs from the ODR fitting process. ```python return result ``` -------------------------------- ### Call ODRPACK95 Routine Source: https://hugomvale.github.io/odrpack-python/reference This is the core call to the ODRPACK95 Fortran routine (_odr). It passes all configured parameters, data, weights, and work arrays. Note that 'beta', 'delta', 'rwork', and 'iwork' are modified in-place by this routine. ```python # Call the ODRPACK95 routine # Note: beta, delta, work, and iwork are modified in place info = _odr( n=n, m=m, q=q, npar=npar, ldwe=ldwe, ld2we=ld2we, ldwd=ldwd, ld2wd=ld2wd, ldifx=ldifx, ldstpd=ldstpd, ldscld=ldscld, f=f, fjacb=jac_beta, fjacd=jac_x, beta=beta, y=ydata, x=xdata, delta=delta, we=weight_y, wd=weight_x, ifixb=ifixb, ifixx=ifixx, stpb=step_beta, stpd=step_delta, sclb=scale_beta, scld=scale_delta, lower=lower, upper=upper, rwork=rwork, iwork=iwork, job=job, ndigit=ndigit, taufac=taufac, sstol=sstol, partol=partol, maxit=maxit, iprint=iprint, errfile=errfile, rptfile=rptfile ) ``` -------------------------------- ### Define observed data points Source: https://hugomvale.github.io/odrpack-python/examples/implicit-model Prepare the observed (x, y) coordinates of the ellipse. The data is structured as a list of lists, where each inner list is a point [x, y]. It is then converted to a NumPy array with shape (2, n) as required by the odr_fit function. A dummy Ydata array is also created as it's a required argument. ```python # Each row represents a point (x, y) of the ellipse X = [[0.50, -0.12], [1.20, -0.60], [1.60, -1.00], [1.86, -1.40], [2.12, -2.54], [2.36, -3.36], [2.44, -4.00], [2.36, -4.75], [2.06, -5.25], [1.74, -5.64], [1.34, -5.97], [0.90, -6.32], [-0.28, -6.44], [-0.78, -6.44], [-1.36, -6.41], [-1.90, -6.25], [-2.50, -5.88], [-2.88, -5.50], [-3.18, -5.24], [-3.44, -4.86]] # We need shape (2, n) Xdata = np.array(X).T # Ydata is not used, but is required Ydata = np.zeros(Xdata.shape[-1]) ``` -------------------------------- ### Perform implicit orthogonal regression Source: https://hugomvale.github.io/odrpack-python/examples/implicit-model Execute the orthogonal distance regression using odr_fit. The task is set to 'implicit-ODR' for implicit models. The function takes the model function, data, initial guess, bounds, and weights as input. Setting report='short' provides a brief computation report. ```python sol = odr_fit(f, Xdata, Ydata, beta0, bounds=(lower, upper), weight_x=weight_x, task='implicit-ODR') ``` -------------------------------- ### Set weight for x-coordinates Source: https://hugomvale.github.io/odrpack-python/examples/implicit-model Set the weight for the x-coordinates. In this case, it's set to 1.0, indicating that the measurement error is assumed to be the same for both x and y coordinates, and no special weighting scheme is needed. ```python weight_x = 1.0 ``` -------------------------------- ### Validate step_beta parameter for odr_fit Source: https://hugomvale.github.io/odrpack-python/reference Checks the `step_beta` argument, ensuring it's a float array with the same shape as `beta0`. This parameter influences the step size in the fitting algorithm. ```python if step_beta is not None: step_beta = np.asarray(step_beta, dtype=np.float64) if step_beta.shape != beta0.shape: raise ValueError("`step_beta` must have the same shape as `beta0`.") ``` -------------------------------- ### Construct OdrResult Object Source: https://hugomvale.github.io/odrpack-python/reference Assembles the final result object 'OdrResult' by populating it with the extracted parameters, calculated values, and information returned by the ODRPACK routine. This includes estimated errors, standard deviations, covariance, convergence information, and work arrays. ```python result = OdrResult( beta=beta, delta=delta, eps=eps, xplusd=xdata+delta, yest=ydata+eps, sd_beta=sd_beta, cov_beta=cov_beta, res_var=rwork[rwork_idx['rvar']], info=info, success=info < 4, nfev=iwork[iwork_idx['nfev']], njev=iwork[iwork_idx['njev']], niter=iwork[iwork_idx['niter']], irank=iwork[iwork_idx['irank']], inv_condnum=rwork[rwork_idx['rcond']], stopreason=stop_message(info), sum_square=rwork[rwork_idx['wss']], sum_square_delta=rwork[rwork_idx['wssdel']], sum_square_eps=rwork[rwork_idx['wsseps']], iwork=iwork, rwork=rwork, ) ``` -------------------------------- ### Perform orthogonal regression Source: https://hugomvale.github.io/odrpack-python/examples/explicit-model Execute the odr_fit function with the defined model, data, initial guess, bounds, and weights to perform the orthogonal regression. ```python sol = odr_fit(f, xdata, ydata, beta0, bounds=(lower, upper), weight_x=weight_x, weight_y=weight_y) ``` -------------------------------- ### Define OdrStop Exception Source: https://hugomvale.github.io/odrpack-python/reference Defines the OdrStop exception class. Raise this exception in your model or Jacobian functions to stop the regression. ```python class OdrStop(Exception): """ Exception to stop the regression. This exception can be raised in the model function or its Jacobians to stop the regression process. """ pass ``` -------------------------------- ### Validate beta0 input for odr_fit Source: https://hugomvale.github.io/odrpack-python/reference Validates the initial parameter estimates (beta0), ensuring it's a rank-1 array. Raises ValueError if beta0 has an incorrect shape. ```python # Check beta0 beta0 = np.asarray(beta0, dtype=np.float64) if beta0.ndim == 1: npar = beta0.size beta = beta0.copy() else: raise ValueError( f"`beta0` must be a rank-1 array of shape `(npar,)`, but has shape {beta0.shape}.") ``` -------------------------------- ### Validate weight_y Input Source: https://hugomvale.github.io/odrpack-python/reference Ensures the weight_y parameter has a compatible shape, supporting scalar, vector, and matrix forms. Raises a ValueError for invalid dimensions. ```python # Check weight_y if weight_y is not None: weight_y = np.asarray(weight_y, dtype=np.float64) if weight_y.shape == (): ldwe = 1 ld2we = 1 weight_y = np.full((q,), weight_y, dtype=np.float64) elif weight_y.shape == (q,): ldwe = 1 ld2we = 1 elif weight_y.shape == (q, q): ldwe = 1 ld2we = q elif weight_y.shape == (q, n) or (weight_y.shape == (n,) and q == 1): ldwe = n ld2we = 1 elif weight_y.shape in ((q, 1, 1), (q, 1, n), (q, q, 1), (q, q, n)): ldwe = weight_y.shape[2] ld2we = weight_y.shape[1] else: raise ValueError( r"`weight_y` must be a array of shape `(q,)`, `(n,)`, `(q, q)`, `(q, n)`, `(q, 1, 1)`, `(q, 1, n)`, `(q, q, 1)`, or `(q, q, n)`. See page 25 of the ODRPACK95 User Guide.") else: ldwe = 1 ld2we = 1 ``` -------------------------------- ### Validate Jacobian Function Output Shapes Source: https://hugomvale.github.io/odrpack-python/reference Checks the output shapes of `jac_beta` and `jac_x` against expected dimensions. Raises a ValueError for incompatible shapes. ```python # Check model jacobians if jac_beta is not None: jac0_beta = jac_beta(xdata, beta0) if jac0_beta.shape[-1] != n or jac0_beta.size != n*npar*q: raise ValueError( "Function `jac_beta` must return an array with shape `(n, npar, q)` or compatible.") if jac_x is not None: jac0_x = jac_x(xdata, beta0) if jac0_x.shape[-1] != n or jac0_x.size != n*m*q: raise ValueError( "Function `jac_x` must return an array with shape `(n, m, q)` or compatible.") ``` -------------------------------- ### Extract Results from Work Arrays Source: https://hugomvale.github.io/odrpack-python/reference This section extracts key results like estimated errors ('eps'), standard deviations of beta ('sd_beta'), and the covariance matrix of beta ('cov_beta') from the 'rwork' array using the indices obtained previously. It also reshapes 'eps' to match the original 'ydata' shape. ```python # Return the result # Extract results without messing up the original work arrays i0_eps = rwork_idx['eps'] eps = rwork[i0_eps:i0_eps+ydata.size].copy() eps = np.reshape(eps, ydata.shape) i0_sd = rwork_idx['sd'] sd_beta = rwork[i0_sd:i0_sd+beta.size].copy() i0_vcv = rwork_idx['vcv'] cov_beta = rwork[i0_vcv:i0_vcv+beta.size**2].copy() cov_beta = np.reshape(cov_beta, (beta.size, beta.size)) ``` -------------------------------- ### Define the implicit ellipse model function Source: https://hugomvale.github.io/odrpack-python/examples/implicit-model This function defines the implicit equation of an ellipse. It takes the coordinates X (shape (2, n)) and the model parameters beta (x0, y0, a, b, theta) and returns the value of the ellipse equation for each point. The equation is set to equal zero for points lying on the ellipse. ```python def f(X: np.ndarray, beta: np.ndarray) -> np.ndarray: x0, y0, a, b, theta = beta x, y = X return ((x - x0)*np.cos(theta) + (y - y0)*np.sin(theta))**2 / a**2 \ + ((y - y0)*np.cos(theta) - (x - x0)*np.sin(theta))**2 / b**2 \ - 1 ``` -------------------------------- ### Validate scale_delta Input Source: https://hugomvale.github.io/odrpack-python/reference Checks the shape and consistency of the scale_delta parameter against xdata. Raises a ValueError if the shape is incompatible. ```python # Check scale_delta if scale_delta is not None: scale_delta = np.asarray(scale_delta, dtype=np.float64) if scale_delta.shape == xdata.shape: ldscld = n elif scale_delta.shape == (m,) and m > 1 and n != m: ldscld = 1 elif scale_delta.shape == (n,) and m > 1 and n != m: ldscld = n scale_delta = np.tile(scale_delta, (m, 1)) else: raise ValueError( "`scale_delta` must either have the same shape as `xdata` or be a rank-1 array of shape `(m,)` or `(n,)`. See page 32 of the ODRPACK95 User Guide.") else: ldscld = 1 ``` -------------------------------- ### Validate step_delta input for odr_fit Source: https://hugomvale.github.io/odrpack-python/reference Checks the `step_delta` argument, which influences the step size for errors in the independent variable. It must match xdata's shape or be a rank-1 array of shape (m,) or (n,). ```python # Check step_delta if step_delta is not None: step_delta = np.asarray(step_delta, dtype=np.float64) if step_delta.shape == xdata.shape: ldstpd = n elif step_delta.shape == (m,) and m > 1 and n != m: ldstpd = 1 elif step_delta.shape == (n,) and m > 1 and n != m: ldstpd = n step_delta = np.tile(step_delta, (m, 1)) else: raise ValueError( "`step_delta` must either have the same shape as `xdata` or be a rank-1 array of shape `(m,)` or `(n,)`. See page 31 of the ODRPACK95 User Guide.") else: ldstpd = 1 ``` -------------------------------- ### Check for NaN Values in Input Arrays Source: https://hugomvale.github.io/odrpack-python/reference Iterates through critical input arrays to detect and raise a ValueError if any NaN values are present. ```python # Check all arrays for NaNs for array, name in [(xdata, 'xdata'), (ydata, 'ydata'), (beta0, 'beta0'), (weight_x, 'weight_x'), (weight_y, 'weight_y'), (lower, 'bounds[0]'), (upper, 'bounds[1]'), (delta0, 'delta0'), (step_beta, 'step_beta'), (step_delta, 'step_delta'), (scale_beta, 'scale_beta'), (scale_delta, 'scale_delta')]: if array is not None and np.isnan(array).any(): raise ValueError(f"`{name}` contains NaN values.") ``` -------------------------------- ### Validate xdata input for odr_fit Source: https://hugomvale.github.io/odrpack-python/reference This code checks the dimensions of xdata, ensuring it's a rank-1 array of shape (n,) or a rank-2 array of shape (m, n). Raises ValueError for incorrect shapes. ```python # Check xdata xdata = np.asarray(xdata, dtype=np.float64) if xdata.ndim == 1: m = 1 elif xdata.ndim == 2: m = xdata.shape[0] else: raise ValueError( f"`xdata` must be a rank-1 array of shape `(n,)` or a rank-2 array of shape `(m, n)`, but has shape {xdata.shape}.") ``` -------------------------------- ### Perform Orthogonal Distance Regression with odr_fit Source: https://hugomvale.github.io/odrpack-python/reference Use odr_fit for orthogonal distance regression. It requires a model function, data, initial parameter estimates, and optional bounds. Ensure data and parameters are correctly shaped. ```python >>> import numpy as np >>> from odrpack import odr_fit >>> xdata = [0.982, 1.998, 4.978, 6.01] >>> ydata = [2.7, 7.4, 148.0, 403.0] >>> beta0 = [2., 0.5] >>> bounds = ([0., 0.], [10., 0.9]) >>> def f(x: np.ndarray, beta: np.ndarray) -> np.ndarray: ... return beta[0] * np.exp(beta[1]*x) >>> sol = odr_fit(f, xdata, ydata, beta0, bounds=bounds) >>> sol.beta array([1.63336897, 0.9 ]) ``` -------------------------------- ### Validate xdata and ydata shape compatibility Source: https://hugomvale.github.io/odrpack-python/reference Ensures the last dimension of xdata and ydata are identical, which is crucial for matching data points. Raises ValueError if they do not match. ```python # Check xdata vs ydata if xdata.shape[-1] == ydata.shape[-1]: n = xdata.shape[-1] else: raise ValueError( f"The last dimension of `xdata` and `ydata` must be identical, but x.shape={xdata.shape} and y.shape={ydata.shape}.") ``` -------------------------------- ### Validate scale_beta parameter for odr_fit Source: https://hugomvale.github.io/odrpack-python/reference Validates the `scale_beta` argument, ensuring it's a float array with the same shape as `beta0`. This parameter affects the scaling of parameters during fitting. ```python if scale_beta is not None: scale_beta = np.asarray(scale_beta, dtype=np.float64) if scale_beta.shape != beta0.shape: raise ValueError("`scale_beta` must have the same shape as `beta0`.") ``` -------------------------------- ### Validate fix_beta parameter for odr_fit Source: https://hugomvale.github.io/odrpack-python/reference Validates the `fix_beta` argument, ensuring it's a boolean array with the same shape as `beta0`. This parameter fixes certain parameters during fitting. ```python # Check other beta related arguments if fix_beta is not None: fix_beta = np.asarray(fix_beta, dtype=np.bool_) if fix_beta.shape != beta0.shape: raise ValueError("`fix_beta` must have the same shape as `beta0`.") ``` -------------------------------- ### Validate Model Function Output Shape Source: https://hugomvale.github.io/odrpack-python/reference Verifies that the model function `f` returns an array with the same shape as `ydata`. Raises a ValueError if shapes do not match. ```python # Check model function f0 = f(xdata, beta0) if f0.shape != ydata.shape: raise ValueError( "Function `f` must return an array with the same shape as `ydata`.") ``` -------------------------------- ### ODR Fit Function Signature Source: https://hugomvale.github.io/odrpack-python/reference This snippet shows the signature of the odr_fit function, detailing its parameters and return type. It is used for solving weighted orthogonal distance regression problems. ```python def odr_fit( f: Callable[[F64Array, F64Array], F64Array], xdata: F64ArrayLike, ydata: F64ArrayLike, beta0: F64ArrayLike, *, weight_x: float | F64ArrayLike | None = None, weight_y: float | F64ArrayLike | None = None, bounds: tuple[F64ArrayLike | None, F64ArrayLike | None] | None = None, task: Literal['explicit-ODR', 'implicit-ODR', 'OLS'] = 'explicit-ODR', fix_beta: BoolArrayLike | None = None, fix_x: BoolArrayLike | None = None, jac_beta: Callable[[F64Array, F64Array], F64Array] | None = None, jac_x: Callable[[F64Array, F64Array], F64Array] | None = None, delta0: F64ArrayLike | None = None, diff_scheme: Literal['forward', 'central'] = 'forward', report: Literal['none', 'short', 'long', 'iteration'] = 'none', maxit: int = 50, ndigit: int | None = None, taufac: float | None = None, sstol: float | None = None, partol: float | None = None, step_beta: F64ArrayLike | None = None, step_delta: F64ArrayLike | None = None, scale_beta: F64ArrayLike | None = None, scale_delta: F64ArrayLike | None = None, rptfile: str | None = None, errfile: str | None = None, ) -> OdrResult: r"""Solve a weighted orthogonal distance regression (ODR) problem, also known as errors-in-variables regression. Parameters ---------- f : Callable[[F64Array, F64Array], F64Array] Function to be fitted, with the signature `f(x, beta)`. It must return an array with the same shape as `y`. xdata : F64ArrayLike Array of shape `(n,)` or `(m, n)` containing the observed values of the explanatory variable(s). ydata : F64ArrayLike Array of shape `(n,)` or `(q, n)` containing the observed values of the response variable(s). When the model is explicit, `ydata` must contain a value for each observation. To ignore specific values (e.g., missing data), set the corresponding entry in `weight_y` to zero. When the model is implicit, `ydata` is not used (but must be defined). beta0 : F64ArrayLike Array of shape `(npar,)` with the initial guesses of the model parameters, within the optional bounds specified by `bounds`. weight_x : float | F64ArrayLike | None Scalar or array specifying how the errors on `xdata` are to be weighted. If `weight_x` is a scalar, then it is used for all data points. If `weight_x` is an array of shape `(n,)` and `m==1`, then `weight_x[i]` represents the weight for `xdata[i]`. If `weight_x` is an array of shape ``` -------------------------------- ### Validate delta0 input for odr_fit Source: https://hugomvale.github.io/odrpack-python/reference Checks the initial estimates for the errors in the independent variable (delta0). It must match the shape of xdata. Raises ValueError if shapes mismatch. ```python # Check delta0 if delta0 is not None: delta0 = np.asarray(delta0, dtype=np.float64) if delta0.shape != xdata.shape: raise ValueError("`delta0` must have the same shape as `xdata`.") delta = delta0.copy() has_delta0 = True else: delta = np.zeros(xdata.shape, dtype=np.float64) has_delta0 = False ``` -------------------------------- ### odr_fit Source: https://hugomvale.github.io/odrpack-python/reference Performs orthogonal distance regression. It allows for detailed control over the fitting process, including maximum iterations, numerical precision, trust region initialization, stopping tolerances, step sizes, scaling, and output reporting. ```APIDOC ## odr_fit ### Description Performs orthogonal distance regression with options for controlling the fitting process and output verbosity. ### Parameters #### Optional Parameters - **report** (str | None) - Controls the level of detail in the output summary. Options are: `'short'` for a brief summary, `'long'` for a detailed summary, and `'iteration'` for detailed summaries including information at each iteration step. - **maxit** (int | None) - Maximum number of allowed iterations. - **ndigit** (int | None) - Number of reliable decimal digits in the computed values of the model function and its Jacobians. - **taufac** (float | None) - Factor ranging from 0 to 1 to initialize the trust region radius. Reducing this may be appropriate if the initial Gauss-Newton step causes an overflow or moves parameters outside the region of interest. - **sstol** (float | None) - Factor ranging from 0 to 1 specifying the stopping tolerance for the sum of the squares convergence. - **partol** (float | None) - Factor ranging from 0 to 1 specifying the stopping tolerance for parameter convergence. - **step_beta** (F64ArrayLike | None) - Array with the same shape as `beta0` containing the relative step sizes for finite difference derivatives with respect to model parameters. - **step_delta** (F64ArrayLike | None) - Array with the same shape as `xdata`, containing the relative step sizes for finite difference derivatives with respect to errors in the explanatory variable. - **scale_beta** (F64ArrayLike | None) - Array with the same shape as `beta0` containing the scale values of the model parameters to improve numerical stability. - **scale_delta** (F64ArrayLike | None) - Array with the same shape as `xdata`, containing the scale values of the errors in the explanatory variable to improve numerical stability. - **rptfile** (str | None) - File name for storing computation reports. Defaults to standard output. - **errfile** (str | None) - File name for storing error reports. Defaults to standard output. ### Returns - **OdrResult** - An object containing the results of the regression. ### References - [1] Jason W. Zwolak, Paul T. Boggs, and Layne T. Watson. Algorithm 869: ODRPACK95: A weighted orthogonal distance regression code with bound constraints. ACM Trans. Math. Softw. 33, 4 (August 2007), 27-es. - [2] Jason W. Zwolak, Paul T. Boggs, and Layne T. Watson. User's Reference Guide for ODRPACK95, 2005. ``` -------------------------------- ### Validate fix_x input for odr_fit Source: https://hugomvale.github.io/odrpack-python/reference Validates the `fix_x` argument, which indicates whether to fix the independent variable. It must match xdata's shape or be a rank-1 array of shape (m,) or (n,). ```python # Check fix_x if fix_x is not None: fix_x = np.asarray(fix_x, dtype=np.bool_) if fix_x.shape == xdata.shape: ldifx = n elif fix_x.shape == (m,) and m > 1 and n != m: ldifx = 1 elif fix_x.shape == (n,) and m > 1 and n != m: ldifx = n fix_x = np.tile(fix_x, (m, 1)) else: raise ValueError( "`fix_x` must either have the same shape as `xdata` or be a rank-1 array of shape `(m,)` or `(n,)`. See page 26 of the ODRPACK95 User Guide.") else: ldifx = 1 ```