Inputs, Outputs, and Checks
Every stage of a numerical project has a contract: the values it receives, the result it produces, and the conditions required for that result to be meaningful. This lesson turns those conditions into clear validation, shape checks, and named outputs.
The previous lesson divided the project into stages. We can now make the boundary of each stage precise by asking:
- What values does this stage receive?
- What values does it return or create?
- What must be true for its result to be meaningful?
The answers form a contract. A function contract describes the inputs a function accepts, the result it produces, and the conditions its caller and implementation must satisfy.
Record more than a variable name
The name x alone does not explain enough. In this project, x should be a
one-dimensional NumPy array of finite floating-point values. Its length should
match the length of y.
Write down the important properties of each value:
| Value | Role | Required properties |
|---|---|---|
config | input | valid seed, at least two points, non-negative noise scale |
x | generated data | one-dimensional, finite, same shape as y |
y | generated data | one-dimensional, finite, same shape as x |
candidate_slopes | fitting input | one-dimensional, finite, not empty |
fitted_slope | fitting result | finite and selected from the candidates |
loss | fitting result | finite and non-negative |
A finite number is neither positive or negative infinity nor NaN.
NaN means “not a number” and commonly appears when a numerical operation has
no valid numerical result.
This table is not merely documentation. Its statements can guide type hints, validation, tests, and error messages.
Validate configuration at the boundary
Configuration describes choices made before the calculation starts. Reject an invalid choice when the configuration enters the computation:
The message names both the invalid field and its rule. Compare it with a vague
message such as "bad configuration", which forces the reader to inspect the
code to discover what failed.
At least two points are required because one point does not provide enough information to inspect a line's direction. A negative noise scale is rejected because the scale represents a non-negative amount of variation.
Check paired arrays before fitting
The fitting function treats x[i] and y[i] as one measured pair. Matching
lengths alone are not enough if one array has shape (4,) and another has
shape (4, 1). NumPy may broadcast those arrays into a two-dimensional result
instead of reporting an error.
Check the intended structure explicitly:
The order of these checks helps interpretation. First confirm the number of dimensions, then compare the complete shapes, and finally check the number of paired observations.
Numerical arrays should also contain usable values:
np.isfinite produces one Boolean value per element. np.all requires every
element to pass.
Check candidate slopes before the search
The search needs at least one finite candidate:
Without the empty-array check, a later operation such as np.argmin fails
farther from the cause. Checking the boundary produces an error that explains
the actual project rule.
Return results with visible meaning
A fitting function produces two different numbers:
The variable names make the tuple positions visible at the call site. A small result record can make the relationship even more explicit:
The fitting function can then return FitResult(slope=..., loss=...), and
callers can read result.slope and result.loss. Either form is reasonable
for this project. The important rule is that the caller should not have to
guess what an unlabeled number means.
Check properties, not one memorized result
Noisy data may change when the seed changes. A useful check therefore targets properties required for every valid run:
These assertions state expectations that should already be guaranteed by the program's implementation. They help expose a programming mistake during development.
Use an explicit exception such as ValueError when rejecting invalid values
supplied at a function boundary. Use an assertion for an internal condition
that correct program logic should make true. Assertions can be disabled when
Python is run with optimization, so they should not be the only protection
against invalid external input.
Run the contracts with valid and invalid values
The example below validates one configuration and one pair of arrays. Change
point_count, noise_scale, or the shape of y to see which contract reports
the problem.
Validate the project inputs
The configuration and data checks run before fitting. Each failure names the value and rule that need attention.
Ready to run.
With the supplied values, all checks pass. If a check fails, the project stops before producing a fitted slope or plot that might look plausible despite invalid input.
Checks support reasoning but do not replace it
A program can verify that arrays have matching shapes, values are finite, and loss is non-negative. These checks cannot establish that:
- the generated data represents a useful real-world process;
- the candidate range contains every scientifically reasonable slope;
- mean squared error is the right measure for a future application;
- a fitted relationship causes one quantity to change another.
Those are questions about the model, data, and interpretation. Mechanical checks protect the computation. They do not turn an unsuitable investigation into a sound one.
Which condition verifies that x and y have exactly the same NumPy shape?
Select one choice, then check.
HintCompare the complete tuples
For example, (4,) and (4, 1) have different shape tuples.
SolutionCompare x.shape with y.shape
Use x.shape == y.shape. Equal sizes do not require the same arrangement,
and equal ndim values do not require equal lengths along each dimension.
What happens when this configuration reaches validate_config?
Select one choice, then check.
HintInspect the value range
The project treats noise scale as a non-negative amount.
SolutionReject the negative noise scale
noise_scale=-0.25 violates the rule noise_scale >= 0.0, so validation
raises ValueError. The point count is valid because 8 is at least 2.
Which value is an output of fit_slope(x, y, candidate_slopes)?
Select one choice, then check.
HintRead the function boundary
Values inside the parentheses are inputs supplied by the caller.
SolutionLoss is produced by fitting
x, y, and candidate_slopes enter the function. The selected slope and
its loss are results produced by the fitting calculation.
Which error message gives the most useful information when
candidate_slopes is empty?
Select one choice, then check.
HintMake the repair visible
The reader should know what to change without searching for the failed rule.
SolutionName the value and its rule
candidate_slopes must not be empty identifies the input and the violated
requirement. The other messages do not explain what needs repair.
Complete check_measured_data so it rejects two-dimensional or mismatched
arrays. The supplied valid arrays must produce:
valid pairs: 3
Validate paired one-dimensional arrays
Ready to run.
HintWrite two separate conditions
First compare each .ndim with 1. Then compare x.shape with y.shape.
SolutionCheck dimensions before matching shapes
The first condition protects the intended one-dimensional representation. The second protects the one-to-one pairing. Keeping them separate also produces a more specific error message.
Write contracts before debugging results
For each project stage, record:
inputs
required properties
outputs
guaranteed properties
Then place checks near the boundary where a rule first becomes known. This turns hidden assumptions into visible program behavior and prevents invalid values from travelling into later calculations.