"Meltdown Mitigation" : operators + conditionals [beware: Exercism potential spoilers]

I’m working on a coding challenge courtesy of Exercism. It’s self-paced study courseware. Even though it is not for-credit, I’d still like to preserve an element of self-discovery so if you are reading this, I am looking for as many hints as you people can provide (the more hints the better) but without providing the complete solution.

The challenge involves conditionals and precedence operators and basic math.

Here is part of the task as outlined by the author of this challenge:

Here is my best attempt:

def is_criticality_balanced(temperature, neutrons_emitted):
   """ Verify criticality is balanced.
 
   :param temperature: temperature value (integer or float)
   :param neutrons_emitted: number of neutrons emitted per second (integer or float)
   :return:  boolean True if conditions met, False if not
 
   A reactor is said to be critical if it satisfies the following conditions:
   - The temperature is less than 800.
   - The number of neutrons emitted per second is greater than 500.
   - The product of temperature and neutrons emitted per second is less than 500 000.
   """
   if (temperature <= 800.00) and (neutrons_emitted > 500.00) and (temperature * neutrons_emitted < 500000.00):
       return True
   else:
       return False

The Doc String is very helpful. When I run the pytest against this solution I’ve written, here is the traceback I see:

FAILED conditionals_test.py::MeltdownMitigationTest::test_is_criticality_balanced - AssertionError: True != False : Expected False but returned True with T=800 and neutrinos=500.01

What this unit test says, according to my understanding, is that when the temperature argument is set to 800.00 and the neutrinos emitted argument is set to 500.01, the expected output is False but in my current iteration above, the function is returning True. That’s what the unit test is saying for those specific parameters. Since this is basic algebra, let’s interpolate those values as arguments into the conditional / algorithm I wrote:

To evaluate that equation, it becomes:

So according to my understanding, as far as I can tell, in this unit test, for these specific arguments (with 800 as temperature and 500.01 as neutrons emitted), the algorithm should evaluate to True but the unit test is saying it is expecting a False end result.

Therefore, my question for all of you is: What am I missing here?

What do I need to change so that my equation evaluates to False with those parameters?

I’ve leveraged a guide on Programiz to learn about “Precedence and Associativity of Operators in Python”. When I try creating a hyperlink, this message board is giving me an error message. Since I can’t share the link directly, an indirect alterantive to access the guide on Programiz I am referring to, you can just Google: precedence of operators in python. It should be the first link.

The most helpful piece of information in that guide identifies how Python evaluates certain math and other symbols from first priority at the top (like (/) down to least priority at the bottom (like not/and/or) and all the many operators in between. There is a chart which shows the hierarchy of Python symbols and precedence. I feel like I have a good understanding of that. But I am clearly still missing something here.

Here is the full unit test for this particular function:

class MeltdownMitigationTest(unittest.TestCase):
   """Test cases for Meltdown mitigation exercise.
   """
 
   @pytest.mark.task(taskno=1)
   def test_is_criticality_balanced(self):
       """Testing border cases around typical points.
 
       T, n == (800, 500), (625, 800), (500, 1000), etc.
 
       """
 
       test_data = ((750, 650, True), (799, 501, True), (500, 600, True),
                    (1000, 800, False), (800, 500, False), (800, 500.01, False),
                    (799.99, 500, False), (500.01, 999.99, False), (625, 800, False),
                    (625.99, 800, False), (625.01, 799.99, False), (799.99, 500.01, True),
                    (624.99, 799.99, True), (500, 1000, False), (500.01, 1000, False),
                    (499.99, 1000, True))
 
       for variant, data in enumerate(test_data, start=1):
           temp, neutrons_emitted, expected = data
           with self.subTest(f'variation #{variant}', temp=temp, neutrons_emitted=neutrons_emitted, expected=expected):
 
               # pylint: disable=assignment-from-no-return
               actual_result = is_criticality_balanced(temp, neutrons_emitted)
               failure_message = (f'Expected {expected} but returned {actual_result} '
                                  f'with T={temp} and neutrinos={neutrons_emitted}')
               self.assertEqual(actual_result, expected, failure_message)
 

Above is just the first function provided by the author of this challenge that I am working with right now. But for what it is worth, here are the additional two, in full:

""" Meltdown Mitigation exercise """


def is_criticality_balanced(temperature, neutrons_emitted):
    """Verify criticality is balanced.

    :param temperature: temperature value (integer or float)
    :param neutrons_emitted: number of neutrons emitted per second (integer or float)
    :return:  boolean True if conditions met, False if not

    A reactor is said to be critical if it satisfies the following conditions:
    - The temperature is less than 800.
    - The number of neutrons emitted per second is greater than 500.
    - The product of temperature and neutrons emitted per second is less than 500000.
    """

    pass


def reactor_efficiency(voltage, current, theoretical_max_power):
    """Assess reactor efficiency zone.

    :param voltage: voltage value (integer or float)
    :param current: current value (integer or float)
    :param theoretical_max_power: power that corresponds to a 100% efficiency (integer or float)
    :return: str one of 'green', 'orange', 'red', or 'black'

    Efficiency can be grouped into 4 bands:

    1. green -> efficiency of 80% or more,
    2. orange -> efficiency of less than 80% but at least 60%,
    3. red -> efficiency below 60%, but still 30% or more,
    4. black ->  less than 30% efficient.

    The percentage value is calculated as
    (generated power/ theoretical max power)*100
    where generated power = voltage * current
    """

    pass


def fail_safe(temperature, neutrons_produced_per_second, threshold):
    """Assess and return status code for the reactor.

    :param temperature: value of the temperature (integer or float)
    :param neutrons_produced_per_second: neutron flux (integer or float)
    :param threshold: threshold (integer or float)
    :return: str one of: 'LOW', 'NORMAL', 'DANGER'

    - `temperature * neutrons per second` < 90% of `threshold` == 'LOW'
    - `temperature * neutrons per second` +/- 10% of `threshold` == 'NORMAL'
    - `temperature * neutrons per second` is not in the above-stated ranges ==  'DANGER'
    """

    pass
```

Here’s a possible hint.

The question mention: if the temperature is less than. What operator exactly are you using to check this condition?

One of the test data is expecting False when the temperature is 800 and the number of neutrons per second is 500. This means your condition (temperature <= 800.00) and (neutrons_emitted > 500.00) is wrong because it’s expecting the temperature to be less and 800 but not equal to 800 and the number of neutrons per second to be greater than 500 but not equal.

Thank you both!

Changing the <= operator to < passed the unit test! When I was wrangling in my Python shell, I thought I tried both those possibilities already, along with other combinations elsewhere in the code block. It’s a lot of trial-and-error and sometimes it’s as if I haven’t saved my script properly before executing it, causing me to overlook the correct answer. Anyways, it works now.