This is relatively easy with PixelMath, but you need multiple expressions and symbols.

Let's define the 'shadows', 'midtones' and 'highlights' sets as a function of two variables, a and b, as follows:

x pertains to shadows if 0 <= x < a

x pertains to midtones if a <= x < b

x pertains to highlights if b <= x < 1

where we are working in the normalized real range [0,1] (0=black and 1=white). Now assume that we want to multiply the shadows set by a constant k1, the midtones set by k2, and the highlights set by k3. This allows us to implement a three-step linear function. The PixelMath implementation is the following:

1. Uncheck the ''Use a single RGB/K expression" option, so we can specify three per-channel expressions.

2. Uncheck the ''Rescale result" option.

3. Define a variable L and five constants: a, b, k1, k2 and k3. For example, we can write this in the Symbols slot of PixelMath:

`L, a=0.25, b=0.60, k1=0.90, k2=1.02, k3=0.95`

4. Enter the following expressions:

`R/K:`

L = CIEL( $T ); $T*iif( L < a, k1, iif( L < b, k2, k3 ) )

G:

$T

B:

$TThese PixelMath expressions implement

*hard sets*, i.e. sets without intersections. An improvement is to implement fuzzy sets, where a pixel can be a member of more than one set at the same time, in different degrees. This implementation is more complex but more useful and flexible. Any takers?

Another way to implement this color correction is with the CurvesTransformation tool, applying per-channel curves with a luminance mask.

Let me know if this helps.