pythonpython-3.xlistmatrixarraylist

Incorrect calculation in the list processing logic based on dependencies between the elements of these lists


My code gives me this incorrect output:

['CT', 'X', 'Z']
[100, 1.0583, 1.0633]
[200, 3.012, 5.873600000000001]
[300, 1.79, 2.5220000000000002]
['Total', 0, 0]

The reason is that 5.873600000000001 is incorrectly calculated because according to list_components_and_hierarchical_relationships, it is indicated that Z is a quantity of 1: ['Z', ['PRODUCT', 1]]. Then,

Then we can build another branch, where Z is a quantity of 1: ['Z', ['PRODUCTO', 1]], and E has a quantity of 4: ['E', [['Z', 4]]]. G depends on E with a quantity of 2: ['G', [['E', 2]]], leaving the calculation as follows:

0.4804 * 1 * 3 + 0.351 * 1 * 2 + 0.77 * 1 * 4 + 0.2168 * 1 * 4 * 2 + 0.2168 * 1 * 3 * 1 = 7.608

enter image description here

This should be the "correct output":

capacity_list = [
['CT', 'X', 'Z'],
[100, 1.0583 * 1, 1.0633 * 1],
[200, 0.351 * 1 * 2 + 0.77 * 1 * 3, 0.4804 * 1 * 3 + 0.351 * 1 * 2 + 0.77 * 1 * 4 + 0.2168 * 1 * 4 * 2 + 0.2168 * 1 * 3 * 1],
[300, 0.895 * 1 * 2, 0.895 * 1 * 2 + 0.244 * 1 * 3],
['Total']
]

Here is my code:

# Initial data
routing_info_list = [
    ['Art.', 'CT', 'Batch_Size', 'Setup_Time', 'Unit_Run_Time'],
    ['X', 100, 30, 0.0083, 1.0583],
    ['Z', 100, 30, 0.0033, 1.0633],
    ['D', 200, 40, 0.011, 0.351],
    ['D', 300, 30, 0.015, 0.895],
    ['E', 200, 10, 0.0, 0.77],
    ['F', 200, 25, 0.0304, 0.4804],
    ['F', 300, 50, 0.004, 0.244],
    ['G', 200, 25, 0.0068, 0.2168]
]

capacity_list = [
    ['CT', 'X', 'Z'],
    [100],
    [200],
    [300],
    ['Total']
]

# Represents the component relationship scheme in first image
list_components_and_hierarchical_relationships = [
    [
        ['X', ['PRODUCT', 1]],
        ['D', [['X', 2]]],
        ['E', [['X', 3]]]
    ],
    [
        ['Z', ['PRODUCT', 1]],
        ['F', [['Z', 3]]],
        ['D', [['Z', 2]]],
        ['E', [['Z', 4]]],
        ['G', [['F', 1]]],
        ['G', [['E', 2]]]
    ]
]

This code seeks to determine the total execution times of the components in a production or manufacturing process, taking into account the dependency relationships between the different components and subcomponents.

# Function to search for Unit_Run_Time in routing_info_list
def search_execution_time_func(articulo, ct):
    for row in routing_info_list[1:]:
        if row[0] == articulo and row[1] == ct:
            return row[4]
    return None

# Function to process a product
def process_product_info_func(components, ct):
    total_time = 0
    for component, dependencies in components:
        run_time = search_execution_time_func(component, ct)
        if run_time is not None:
            # Multiply by the dependencies
            total_quantity = 1
            for dep in dependencies:
                if isinstance(dep, list) and dep[0] != 'PRODUCT':
                    total_quantity *= dep[1]
            print( str(run_time) + " hrs * " + str(total_quantity) )
            total_time += run_time * total_quantity
    return total_time

# Process each CT row from the product capacity list for each column
for row in capacity_list[1:]:
    ct = row[0]
    times = []
    for product_idx, product in enumerate(list_components_and_hierarchical_relationships):
        total_time = process_product_info_func(product, ct)
        times.append(total_time)
    row.extend(times)

# Calculate the 'Total' row
# Get the number of columns, excluding 'CT'
num_columns = len(capacity_list[0]) - 1
# Sum the values of each column, ignoring the header row and the 'CT' column
for col in range(1, num_columns + 1):
    total_sum = sum(row[col] for row in capacity_list[1:-1])
    capacity_list[-1][col] = total_sum

# Display the final result
for row in capacity_list: print(row)

enter image description here

What should I do to correct it, and tell me how it would give the correct output, adding the terms of each branch of the components according to the diagram?


Solution

  • For this task I'd use module:

    import networkx as nx
    
    
    def create_hierarchical_graph(relationships_list):
        for relationships in relationships_list:
            G = nx.DiGraph()
            root = None
            for item in relationships:
                node = item[0]
                connections = item[1]
    
                if connections[0] == "PRODUCT":
                    G.add_edge("PRODUCT", node, weight=connections[1])
                    root = node
                else:
                    for connection in connections:
                        parent_node = connection[0]
                        weight = connection[1]
                        G.add_edge(parent_node, node, weight=weight)
            yield G, root
    
    
    def get_weight(G, path):
        total = 1
        for u, v in zip(path[:-1], path[1:]):
            total *= G.edges[u, v]["weight"]
        return total
    
    
    list_components_and_hierarchical_relationships = [
        [
            ["X", ["PRODUCT", 1]],
            ["D", [["X", 2]]],
            ["E", [["X", 3]]],
        ],
        [
            ["Z", ["PRODUCT", 1]],
            ["F", [["Z", 3]]],
            ["D", [["Z", 2]]],
            ["E", [["Z", 4]]],
            ["G", [["F", 1]]],
            ["G", [["E", 2]]],
        ],
    ]
    
    
    routing_info_list = [
        ["Art.", "CT", "Batch_Size", "Setup_Time", "Unit_Run_Time"],
        ["X", 100, 30, 0.0083, 1.0583],
        ["Z", 100, 30, 0.0033, 1.0633],
        ["D", 200, 40, 0.011, 0.351],
        ["D", 300, 30, 0.015, 0.895],
        ["E", 200, 10, 0.0, 0.77],
        ["F", 200, 25, 0.0304, 0.4804],
        ["F", 300, 50, 0.004, 0.244],
        ["G", 200, 25, 0.0068, 0.2168],
    ]
    
    # transform routing info list to
    # easily find unit run time
    unit_run_times = {}
    for l in routing_info_list[1:]:
        unit_run_times.setdefault(l[1], {}).setdefault(l[0], {})
        unit_run_times[l[1]][l[0]] = l[-1]
    
    
    for G, root in create_hierarchical_graph(list_components_and_hierarchical_relationships):
        print(f"{root=}")
        for CT in [100, 200, 300]:
            s = 0
            for a in unit_run_times[CT]:
                for p in nx.all_simple_paths(G, "PRODUCT", a):
                    s += get_weight(G, p) * unit_run_times[CT][a]
            print(CT, s)
        print("-" * 80)
    

    Prints:

    root='X'
    100 1.0583
    200 3.012
    300 1.79
    --------------------------------------------------------------------------------
    root='Z'
    100 1.0633
    200 7.6080000000000005
    300 2.5220000000000002
    --------------------------------------------------------------------------------