Derive the Units

10

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

Beta Decay

Posted 2017-04-12T10:24:21.543

Reputation: 21 478

Related. – Martin Ender – 2017-04-12T10:34:57.030

Does input (output) need to be taken (given) as a string, or are other types / structures, e.g. symbols, acceptable? – Julian Wolf – 2017-04-17T21:06:31.413

@JulianWolf No, I/O has to be as strings – Beta Decay – 2017-04-17T21:11:28.710

Answers

12

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.

Martin Ender

Posted 2017-04-12T10:24:21.543

Reputation: 184 808

1

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])
)

darrylyeo

Posted 2017-04-12T10:24:21.543

Reputation: 6 214