curves#

Implement demand, supply and related curves.

freeride.curves.ppf_sum(*curves, comparative_advantage=True)[source]#

Combine production possibilities frontiers.

Parameters:
  • *curves (sequence of AffineElement) – PPF curves to aggregate.

  • comparative_advantage (bool, optional) – When True curves are ordered by slope from steepest to flattest before summation, highlighting comparative advantage.

Returns:

The shifted and vertically stacked PPF segments forming the aggregate frontier.

Return type:

list of AffineElement

class freeride.curves.BaseAffine(intercept=None, slope=None, elements=None, inverse=True, sum_elements=True)[source]#

Bases: object

__init__(intercept=None, slope=None, elements=None, inverse=True, sum_elements=True)[source]#

Initialize the BaseAffine object.

Parameters:
  • intercept (float or list of floats, optional) – The intercept(s) of the affine transformation. Default is None.

  • slope (float or list of floats, optional) – The slope(s) of the affine transformation. Default is None.

  • elements (list of AffineElement, optional) – List of AffineElement objects. If provided, it will override intercept and slope. Default is None.

  • inverse (bool, optional) – Indicates if the transformation should be inverted. Default is True.

  • sum_elements (bool, optional) – Whether to sum elements together (True) or keep them as separate pieces (False). Default is True.

Raises:

ValueError – If the lengths of slope and intercept do not match.

property has_perfectly_elastic_segment#

Whether the curve contains a perfectly elastic segment.

Type:

bool

property has_perfectly_inelastic_segment#

Whether the curve contains a perfectly inelastic segment.

Type:

bool

property has_perfect_segment#

Whether the curve contains a perfectly elastic or inelastic segment.

Type:

bool

classmethod from_two_points(x1, y1, x2, y2)[source]#

Creates an Affine object from two points.

classmethod from_points(xy_points)[source]#

Creates an Affine object from two points.

In the future, this might be extended to allow for three or more points.

classmethod from_formula(equation: str)[source]#
horizontal_shift(delta, inplace=True)[source]#
vertical_shift(delta, inplace=True)[source]#
property q_intercept#

Return the quantity intercept(s) for the affine elements.

class freeride.curves.Demand(intercept=None, slope=None, elements=None, inverse=True)[source]#

Bases: Affine

__init__(intercept=None, slope=None, elements=None, inverse=True)[source]#

Initializes a Demand curve object.

q(p)[source]#

Calculate quantity demanded at price p, handling perfectly elastic segments.

For horizontal demand at price P*: - q(P*) = 0 (with warning about indeterminacy) - q(P > P*) = 0 - q(P < P*) = ∞

consumer_surplus(p, q=None)[source]#
total_revenue()[source]#
marginal_revenue()[source]#
class freeride.curves.Supply(intercept=None, slope=None, elements=None, inverse=True)[source]#

Bases: Affine

__init__(intercept=None, slope=None, elements=None, inverse=True)[source]#

Initializes a Supply curve object.

q(p)[source]#

Calculate quantity supplied at price p, handling perfectly elastic segments.

For horizontal supply at price P*: - q(P*) = 0 (with warning about indeterminacy) - q(P > P*) = ∞ - q(P < P*) = 0

producer_surplus(p, q=None)[source]#
class freeride.curves.Constraint(p1, p2, endowment=1, name1=None, name2=None, elements=None, inverse=True)[source]#

Bases: BaseAffine

__init__(p1, p2, endowment=1, name1=None, name2=None, elements=None, inverse=True)[source]#

Incomplete.

class freeride.curves.PPF(intercept=None, slope=None, elements=None, inverse=True)[source]#

Bases: BaseAffine

Production possibilities frontier.

__init__(intercept=None, slope=None, elements=None, inverse=True)[source]#

Initializes a PPF object with given slope and intercept or elements.

Parameters:
  • intercept (float or list of float, optional) – The y-intercept(s) of the elements.

  • slope (float or list of float, optional) – The slope(s) of the elements.

  • elements (list of AffineElement, optional) – A list of AffineElements whose horizontal sum defines the PPF.

  • inverse (bool, optional) – When inverse is True, it is assumed that equations are in the form P(Q).

Raises:

ValueError – If the lengths of slope and intercept do not match.

horizontal_shift(delta, inplace=True)[source]#
vertical_shift(delta, inplace=True)[source]#
plot(ax=None, set_lims=True, max_q=None, label=True, backend='mpl', **kwargs)[source]#

Plot the ppf.

class freeride.curves.AffineElement(*args: Any, **kwargs: Any)[source]#

Bases: PolyBase

This class extends the PolyBase class and represents an affine function commonly used in supply and demand curves. This does allow for negative quantities.

Parameters:
  • (float) (slope)

  • (float)

  • (bool (inverse) – and intercept. Defaults to True.

  • optional) (If True, interprets the parameters as inverse slope) – and intercept. Defaults to True.

vertical_shift(delta: float):

Shift the curve vertically by the given amount.

horizontal_shift(delta: float):

Shift the curve horizontally by the given amount.

price_elasticity(p: float) float:[source]#

Calculate the point price elasticity at a given price.

midpoint_elasticity(p1: float, p2: float) float:[source]#

Calculate the price elasticity between two prices using the midpoint formula.

plot(ax=None, textbook_style=True, max_q=10, color='black', linewidth=2, label=True):

Plot the supply or demand curve.

intercept(float)#
Type:

The intercept of the affine function.

slope(float)#
Type:

The slope of the affine function.

q_intercept(float)#
Type:

The quantity intercept of the affine function.

Example

To create an AffineElement object and use its methods:

>>> demand_curve = Affine(10.0, -1.0)
>>> demand_curve.q(4.0)  # Calculate the quantity at price p=4.0
6.0
__init__(intercept, slope, inverse=True, symbols=None)[source]#

Initialize an AffineElement with the given intercept and slope.

This method creates an instance of the class with the specified intercept and slope. The parameters can be interpreted as inverse slope and intercept if the inverse parameter is True.

Parameters:
  • (float) (slope)

  • (float)

  • (bool (inverse) – and intercept. Defaults to True.

  • optional) (If True, interprets the parameters as inverse slope) – and intercept. Defaults to True.

Returns:

AffineElement

Return type:

An AffineElement object representing the supply or demand curve.

Example

>>> supply_curve = AffineElement(10.0, 2.0)
vertical_shift(delta, inplace=True)[source]#

Shift the curve vertically by the given amount.

This method shifts the supply or demand curve vertically by the specified amount delta. A positive delta shifts the demand curve to the right. A negative delta shifts the supply curve to the left.

Parameters:

(float) (delta)

Return type:

None

Example

>>> supply_curve = Affine(10.0, -2.0)
>>> supply_curve.vertical_shift(2.0)
horizontal_shift(delta, inplace=True)[source]#

Shift the curve horizontally by the given amount.

This method shifts the supply or demand curve horizontally by the specified amount delta. Positive values of delta shift the curve to the right.

Parameters:

(float) (delta)

Return type:

None

Example

>>> demand_curve = Affine(10.0, -2.0)
>>> demand_curve.horizontal_shift(1.0)
price_elasticity(p)[source]#

Calculate the point price elasticity at a given price.

This method calculates the point price elasticity at the specified price p.

Parameters:

(float) (p)

Returns:

float

Return type:

The point price elasticity.

Example

>>> demand_curve = Affine(10.0, -2.0)
>>> demand_curve.price_elasticity(4.0)
midpoint_elasticity(p1, p2)[source]#

Find price elasticity between two prices using the midpoint formula.

This method calculates the price elasticity between two prices, p1 and p2, using the midpoint formula.

Parameters:
  • (float) (p2)

  • (float)

Returns:

float

Return type:

The price elasticity between the two prices.

Example

>>> demand_curve = Affine(10.0, -2.0)
>>> demand_curve.midpoint_elasticity(3.0, 5.0)
plot(ax=None, textbook_style=True, max_q=None, label=True, **kwargs)[source]#

Plot the affine curve.

Parameters:
  • ax (matplotlib.axes._axes.Axes, optional) – The matplotlib axis to use for plotting. If not provided, the current axes will be used or a new figure will be created.

  • textbook_style (bool, optional) – If True, use textbook-style plot formatting with clean axes and appropriate labels. Defaults to True.

  • max_q (float, optional) – The maximum quantity value for the plot. If not specified, a sensible default will be calculated based on the curve’s intercepts.

  • label (bool, optional) – If True, label the curve and axes. Defaults to True.

  • **kwargs (dict) – Additional keyword arguments passed to matplotlib’s plot function. Common options include: - color : str, default ‘black’ - linewidth : int, default 2 - linestyle : str, default ‘-’ - alpha : float, default 1.0

Returns:

The axes object containing the plot, which can be further customized.

Return type:

matplotlib.axes._axes.Axes

Example

>>> demand_curve = AffineElement(10.0, -2.0)
>>> demand_curve.plot()
plot_area(p, q=None, ax=None, zorder=-1, color=None, alpha=None, force=False)[source]#

Plot surplus region

class freeride.curves.Affine(intercept=None, slope=None, elements=None, inverse=True, sum_elements=True)[source]#

Bases: BaseAffine

A class to represent a piecewise affine function.

__init__(intercept=None, slope=None, elements=None, inverse=True, sum_elements=True)[source]#

Initializes an Affine object with given slopes and intercepts or elements. The slopes correspond to elements, which are differentiated from pieces.

When sum_elements=True: elements are horizontally summed to create aggregate pieces. When sum_elements=False: elements are kept as separate pieces (for discontinuous functions).

Parameters:
  • intercept (float, list of float, optional) – The y-intercept(s) of the elements.

  • slope (float, list of float, optional) – The slope(s) of the elements.

  • elements (list of AffineElement, optional) – A list of AffineElements whose horizontal sum defines the Affine object.

  • inverse (bool, optional) – When inverse is True, it is assumed that equations are in the form P(Q).

  • sum_elements (bool, optional) – Whether to sum elements together (True) or keep them as separate pieces (False). Default is True.

Raises:

ValueError – If the lengths of slope and intercept do not match.

q(p)[source]#
p(q)[source]#
equation(inverse=False)[source]#
price_elasticity(p, delta=1e-06)[source]#
property inverse_equation#
plot(ax=None, set_lims=True, max_q=None, label=True, **kwargs)[source]#

Plot the Affine object.

Parameters:
  • ax (matplotlib.axes.Axes, optional) – The axes on which to plot. If None, a new figure and axes will be created.

  • set_lims (bool, optional) – Whether to automatically set the limits for the axes. Default is True.

  • max_q (float, optional) – The maximum quantity to consider for setting the x-axis limit. If None, it will be automatically determined.

  • label (bool, optional) – Whether to add curve/axis labels. Default True.

  • **kwargs (dict) – Additional keyword arguments for controlling line color, style, etc.

Returns:

ax

Return type:

matplotlib.axes.Axes

plot_surplus(p, q=None, ax=None, color=None, max_q=None, alpha=None)[source]#
surplus(p, q=None)[source]#

Returns surplus area. The areas are negative for producer surplus.

freeride.curves.intersection(element1, element2)[source]#

Return the intersection of two affine elements.

The result is a 1D array [p, q] giving the price and quantity at the intersection. When either line is perfectly vertical (slope == np.inf) or perfectly horizontal (slope == 0) the intersection is computed directly. If both lines are vertical or both horizontal, a LinAlgError is raised.

Parameters:
  • element1 (AffineElement) – Lines for which to compute the intersection.

  • element2 (AffineElement) – Lines for which to compute the intersection.

Returns:

[p, q] of the intersection point.

Return type:

numpy.ndarray

Raises:

numpy.linalg.LinAlgError – If the lines are parallel.

Examples

>>> line1 = AffineElement(intercept=12, slope=-1)
>>> line2 = AffineElement(intercept=0, slope=2)
>>> intersection(line1, line2)
array([8., 4.])
freeride.curves.blind_sum(*curves)[source]#

Computes the horizontal summation of AffineElement objects.

Parameters:

*curves (AffineElement) – The objects to be summed.

Returns:

The horizontal summation of the input curves represented as an AffineElement object. Returns None if no curves are provided.

Return type:

AffineElement

freeride.curves.horizontal_sum(*curves)[source]#

Compute active curves at different price midpoints based on the p-intercepts of input curves.

Parameters:

*curves (sequence of AffineElements) – Variable-length argument list of Affine curve objects for which the active curves are to be found.

Returns:

A tuple containing three elements: - active_curves (list): List of AffineElement objects representing

the active curves at each price midpoint.

  • cutoffs (list): List of unique p-intercepts sorted in ascending order.

  • midpoints (list): List of midpoints computed based on the cutoffs.

Return type:

tuple

class freeride.curves.Revenue(intercept=None, linear_coef=None, quadratic_coef=None, elements=None)[source]#

Bases: BaseQuadratic

Piecewise quadratic revenue curve.

This class represents total revenue as a function of quantity. It is typically generated from a Demand curve and inherits all functionality of BaseQuadratic.

classmethod from_demand(demand) Revenue[source]#

Construct a Revenue curve from a Demand instance.

class freeride.curves.MarginalRevenue(intercept=None, slope=None, elements=None, inverse=True, sum_elements=True)[source]#

Bases: Affine

Piecewise linear marginal revenue curve.

This class represents marginal revenue as a function of quantity. These curves will not necessarily be continuous for piecewise Demand. Uses Affine with sum_elements=False to keep pieces separate for discontinuities.

classmethod from_demand(demand) MarginalRevenue[source]#

Construct a MarginalRevenue curve from a Demand instance.