10
\$\begingroup\$

Challenge

Given a list of SI base units, a list of equations and a target, you must derive the units of the target using only the base units.

Derived Units

From Wikipedia:

The International System of Units (SI) specifies a set of seven base units from which all other SI units of measurement are derived. Each of these other units (SI derived units) is either dimensionless or can be expressed as a product of powers of one or more of the base units.

For example, the SI derived unit of area is the square metre (m2), and the SI derived unit of density is the kilogram per cubic metre (kg/m3 or kg m−3).

The seven SI base units are:

  • Ampere, A
  • Candela, cd
  • Kelvin, K
  • Kilogram, kg
  • Metre, m
  • Mole, mol
  • Second, s

Example

Input

Base units:

d [m]
m [kg]
t [s]

Equations:

v = d/t
a = v/t
F = m*a
E = F*d

Target:

E

Output

E [kg*m*m/s/s]

Input

Base units:

G [cd]
L [m]
y [A]
a [K]

Equations:

T = y*y/L
A = T*G

Target:

A

Output

A [cd*A*A/m]

Rules

The units will be always be given in the form

a [b]

Where a will be a single uppercase or lowercase alphabetical letter and b will be a unit (one or more characters).

The equation will be in the form

a = c

Where c will be an expression which will only ever use previously defined units and the operators * and /.

Powers must be expanded. For example, the unit of area is officially m^2, but you should represent this as m*m. The same applies to negative powers such as speed (m*s^-1) which should be represented as a division: m/s. Similarly, the units for acceleration, m/s^2 or m*s^-2, should be represented as m/s/s.

You do not have to do any cancelling out. For example, an output C*s/kg/s is valid even though it can be cancelled down to C/kg.

There is no specific order for the multiplication: kg*s/m, s/m*kg, s*kg/m are all valid (but /m*s*kg is invalid).

Note: You will never have to divide by a derived unit.

Winning

The shortest code in bytes wins

\$\endgroup\$
  • \$\begingroup\$ Related. \$\endgroup\$ – Martin Ender Apr 12 '17 at 10:34
  • \$\begingroup\$ Does input (output) need to be taken (given) as a string, or are other types / structures, e.g. symbols, acceptable? \$\endgroup\$ – Julian Wolf Apr 17 '17 at 21:06
  • \$\begingroup\$ @JulianWolf No, I/O has to be as strings \$\endgroup\$ – Beta Decay Apr 17 '17 at 21:11
12
\$\begingroup\$

Retina, 50 48 bytes

 =

+`((.) (.+)\D*)\2(?!\w*])
$1$3
A-2`
](.).
$1

Try it online!

Explanation

 =

Remove all equals signs together with the space in front of them. Who needs those anyway...

+`((.) (.+)\D*)\2(?!\w*])
$1$3

This performs the substitutions of known quantities. It repeatedly matches a quantity definition (the quantity is any character in front of a space and the definition the string after it), as well as some place after the definition where that quantity is used, and insert the definition for the usage. We exclude units from those matches (by ensuring that there is no ] after the match), so that we don't replace [m] with [[kg]] for example. This substitution is repeated until the regex no longer matches (which means that there are no usages of a quantity left, and all lines have been turned into expressions of units).

A-2`

Discard all but the last line.

](.).
$1

Finally, remove extraneous square brackets. Basically, we want to keep the first [ and the last ] but discard all others. Those others always appear with an operator in between, so either as ]*[ or as ]/[. But more importantly, those are the only cases where a ] is followed by two more characters. So we match all ] with two characters after them, and replace that with the second of those three characters to retain the operator.

\$\endgroup\$
1
\$\begingroup\$

JavaScript (ES6), 155 153 152 bytes

(U,E,T)=>(u={},U.map(x=>u[x[0]]=x.slice(3,-1)),e={},E.map(x=>e[x[0]]=x.slice(4)).map(_=>s=s.replace(r=/[A-z]/g,m=>e[m]||m),s=e[T]),s.replace(r,m=>u[m]))

Takes base units and equations as arrays of strings.

f=
(U,E,T)=>(u={},U.map(x=>u[x[0]]=x.slice(3,-1)),e={},E.map(x=>e[x[0]]=x.slice(4)).map(_=>s=s.replace(r=/[A-z]/g,m=>e[m]||m),s=e[T]),s.replace(r,m=>u[m]))

console.log(
  f(
    ['d [m]', 'm [kg]', 't [s]'],
    ['v = d/t', 'a = v/t', 'F = m*a', 'E = F*d'],
    'E'
  )
)
console.log(
  f(
    ['G [cd]', 'L [m]', 'y [A]', 'a [K]'],
    ['T = y*y/L', 'A = T*G'],
    'A'
  )
)

Explanation

// Base Units, Equations, Target
(U,E,T)=>(
    // Map variable names to SI units
    u={},
    U.map(x=>u[x[0]]=x.slice(3,-1)), // x[0] is the variable name,
                                     // x.slice(3,-1) is the unit

    // Map variable names to equations
    e={},
    E.map(x=>e[x[0]]=x.slice(4)) // x[0] is the variable name,
                                 // x.slice(4) is the unit

    // (Initialize return string to the target variable's equation
    // using the (useless) second argument to .map() below)
    // s=e[T]

    // For as many times as there are equations (chained from above),
    .map(_=>
        // Substitute each variable with its equivalent expression
        // if there is one.
        s=s.replace(
            r=/[A-z]/g, // Save this regex for final step.
            m=>e[m]||m
        ),

        // The working string variable is initialized here.
        s=e[T]
    ),

    // Substitute remaining variables with SI units and return. 
    s.replace(r,m=>u[m])
)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.