// Numbas version: finer_feedback_settings {"name": "Adrian's copy of Solve a linear programming problem", "extensions": ["jsxgraph", "optimisation"], "custom_part_types": [], "resources": [], "navigation": {"allowregen": true, "showfrontpage": false, "preventleave": false, "typeendtoleave": false}, "question_groups": [{"pickingStrategy": "all-ordered", "questions": [{"functions": {"profit": {"definition": "profitx*x+profity*y", "type": "number", "language": "jme", "parameters": [["x", "number"], ["y", "number"]]}, "best_by": {"definition": "// l1 is a list of indices on l2\n// return the element of l1 which has the biggest corresponding value in l2 \n// (i.e. i such that l2[l1[i]] is biggest)\n\nvar best_1 = null;\nvar best_2 = null;\nfor(var i=0;ibest_2) {\n best_2 = l2[l1[i]];\n best_1 = l1[i];\n }\n}\nreturn best_1", "type": "number", "language": "javascript", "parameters": [["l1", "list"], ["l2", "list"]]}}, "ungrouped_variables": [], "name": "Adrian's copy of Solve a linear programming problem", "tags": ["constraints", "linear programming", "objective function", "template"], "preamble": {"css": "", "js": "function userinput_diagram() {\n\nwith(question.unwrappedVariables) {\n\n var options = {\n x_bound: boundx, \n y_bound: boundy\n };\n\n options.objective_line_coordinates = [[0,0],[1,-profitx/profity]];\n \n function getStudentAnswer(path) {\n var part = question.getPart(path);\n return ko.computed(function() {\n return parseFloat(part.display.studentAnswer());\n });\n }\n \n options.minimum_x = getStudentAnswer('p0g0');\n options.minimum_y = getStudentAnswer('p0g1');\n\n var x_coefficient_1 = getStudentAnswer('p1g0');\n var y_coefficient_1 = getStudentAnswer('p1g1');\n var total_1 = getStudentAnswer('p1g2');\n options.inequality_1_coordinates = [ko.computed(function() {\n return [-total_1(),x_coefficient_1(),y_coefficient_1()];\n })];\n\n options.inequality_1_ok = ko.computed(function() {\n return !(isNaN(x_coefficient_1()) || isNaN(y_coefficient_1()) || isNaN(total_1()));\n });\n\n var x_coefficient_2 = getStudentAnswer('p1g3');\n var y_coefficient_2 = getStudentAnswer('p1g4');\n var total_2 = getStudentAnswer('p1g5');\n options.inequality_2_coordinates = [ko.computed(function() {\n return [-total_2(),x_coefficient_2(),y_coefficient_2()];\n })];\n\n options.inequality_2_ok = ko.computed(function() {\n return !(isNaN(x_coefficient_2()) || isNaN(y_coefficient_2()) || isNaN(total_2()));\n });\n\n var result = Numbas.extensions.optimisation.linear_programming_board(options);\n $(question.display.html).find('.lp-graph').html('').append(result.div);\n}\n}\n\nfunction advice_diagram() {\nwith(question.unwrappedVariables) {\n\n var result = Numbas.extensions.optimisation.linear_programming_board({\n x_bound: boundx,\n y_bound: boundy,\n objective_line_coordinates: [[0,best_profit_float/profity],[1,(best_profit_float-profitx)/profity]],\n minimum_x: xconstraint,\n minimum_y: yconstraint,\n inequality_1_coordinates: [-totalresource1, resource1x, resource1y],\n inequality_2_coordinates: [-totalresource2, resource2x, resource2y]\n });\n $(question.display.html).find('#advicediagram').html('').append(result.div);\n}\n}\n\nquestion.signals.on('HTMLAttached',function() {\n userinput_diagram();\n advice_diagram();\n});\n"}, "advice": "

a)

\n

The existing orders give two constraints:

\n

\\begin{align}
x &\\geq \\var{xconstraint} \\\\
y &\\geq \\var{yconstraint}
\\end{align}

\n

b)

\n

The limits on the two resources, and the amounts of each resource used to produce a unit of each product, give two further constraints:

\n

\\begin{align}
\\simplify{{resource1x}x + {resource1y}y} &\\leq \\var{totalresource1} \\\\
\\simplify{{resource2x}x + {resource2y}y} &\\leq \\var{totalresource2}
\\end{align}

\n

c)

\n

The objective function to be maximised is the total profit earned, that is, the sum of the profits earned from each unit made:

\n

\\[ \\simplify{{profitx}x + {profity}y} \\]

\n

d)

\n

The solution graph goes here

\n

It is clear that the minimum profit is given by producing enough {product_1s} and {product_2s} so that the existing demand is met and no more. You can see this by moving the objective function line down to the intersection of the two minimum constraint lines - there are no other points inside the feasible region under the objective line.

\n

Next, drag the objective function line upwards until there are no points above the objective line in the feasible region. At this point, the objective line touches the intersection of the lines representing the constraints for {line_names[best_lines[0]]} and {line_names[best_lines[1]]}.

\n

You can find the coordinates of this point by solving the equations for these two lines:

\n

\\[ \\simplify{{resource1x}x + {resource1y}y = {totalresource1}} \\]\\[ \\simplify{{resource2x}x + {resource2y}y = {totalresource2}} \\]

\n

\\[ \\simplify{{resource2x}x + {resource2y}y = {totalresource2}} \\]\\[ x = \\var{xconstraint} \\]\\[ y = \\var{yconstraint} \\]

\n

The solution to this system of equations is $x = \\var{best_x}$, $y = \\var{best_y}$, giving a profit of

\n

\\[ \\text{Profit} = \\simplify[]{{profitx}*{best_x} + {profity}*{best_y}} = \\text{£}\\var{best_profit} \\]

", "rulesets": {}, "parts": [{"prompt": "

Let $x$, $y$ be the number of units of {product_1s} and {product_2s} produced, respectively.

\n

What are the constraints on production resulting from the existing orders?

\n

$x \\geq$ [[0]]

\n

$y \\geq$ [[1]]

", "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "gaps": [{"allowFractions": false, "variableReplacements": [], "maxValue": "xconstraint", "minValue": "xconstraint", "variableReplacementStrategy": "originalfirst", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}, {"allowFractions": false, "variableReplacements": [], "maxValue": "yconstraint", "minValue": "yconstraint", "variableReplacementStrategy": "originalfirst", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}], "showCorrectAnswer": true, "scripts": {}, "marks": 0, "type": "gapfill"}, {"prompt": "

Now enter the constraints given by the availability of {resource_1} and {resource_2}:

\n

{capitalise(resource_1)}: [[0]] $x + $ [[1]] $y \\le $ [[2]]

\n

{capitalise(resource_2)}: [[3]] $x + $ [[4]] $y \\le $ [[5]]

", "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "gaps": [{"allowFractions": false, "variableReplacements": [], "maxValue": "resource1x", "minValue": "resource1x", "variableReplacementStrategy": "originalfirst", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}, {"allowFractions": false, "variableReplacements": [], "maxValue": "resource1y", "minValue": "resource1y", "variableReplacementStrategy": "originalfirst", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}, {"allowFractions": false, "variableReplacements": [], "maxValue": "totalresource1", "minValue": "totalresource1", "variableReplacementStrategy": "originalfirst", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}, {"allowFractions": false, "variableReplacements": [], "maxValue": "resource2x", "minValue": "resource2x", "variableReplacementStrategy": "originalfirst", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}, {"allowFractions": false, "variableReplacements": [], "maxValue": "resource2y", "minValue": "resource2y", "variableReplacementStrategy": "originalfirst", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}, {"allowFractions": false, "variableReplacements": [], "maxValue": "totalresource2", "minValue": "totalresource2", "variableReplacementStrategy": "originalfirst", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}], "showCorrectAnswer": true, "scripts": {}, "marks": 0, "type": "gapfill"}, {"prompt": "

Given the information on profits for {product_1s} and {product_2s}, write down the objective function which is to be maximised: [[0]]

", "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "gaps": [{"vsetrangepoints": 5, "expectedvariablenames": [], "checkingaccuracy": 0.001, "vsetrange": [0, 1], "showpreview": true, "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "showCorrectAnswer": true, "answersimplification": "all", "scripts": {}, "answer": "{profitx}*x+{profity}*y", "marks": 1, "checkvariablenames": false, "checkingtype": "absdiff", "type": "jme"}], "showCorrectAnswer": true, "scripts": {}, "marks": 0, "type": "gapfill"}, {"prompt": "

Input diagram goes here

\n

Drag the objective line on the diagram above to find the position which gives the maximum profit.

\n

Round your answers down to the nearest integer, end enter them below:

\n

Produce [[0]] {product_1s} and [[1]] {product_2s}, earning £ [[2]] in profit.

", "variableReplacements": [], "variableReplacementStrategy": "originalfirst", "gaps": [{"integerPartialCredit": 0, "integerAnswer": true, "allowFractions": false, "variableReplacements": [{"variable": "xconstraint", "part": "p0g0", "must_go_first": true}, {"variable": "yconstraint", "part": "p0g1", "must_go_first": true}, {"variable": "resource1x", "part": "p1g0", "must_go_first": true}, {"variable": "resource1y", "part": "p1g1", "must_go_first": true}, {"variable": "totalresource1", "part": "p1g2", "must_go_first": true}, {"variable": "resource2x", "part": "p1g3", "must_go_first": true}, {"variable": "resource2y", "part": "p1g4", "must_go_first": true}, {"variable": "totalresource2", "part": "p1g5", "must_go_first": true}], "maxValue": "best_x", "minValue": "best_x", "variableReplacementStrategy": "alwaysreplace", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}, {"integerPartialCredit": 0, "integerAnswer": true, "allowFractions": false, "variableReplacements": [{"variable": "xconstraint", "part": "p0g0", "must_go_first": true}, {"variable": "yconstraint", "part": "p0g1", "must_go_first": true}, {"variable": "resource1x", "part": "p1g0", "must_go_first": true}, {"variable": "resource1y", "part": "p1g1", "must_go_first": true}, {"variable": "totalresource1", "part": "p1g2", "must_go_first": true}, {"variable": "resource2x", "part": "p1g3", "must_go_first": true}, {"variable": "resource2y", "part": "p1g4", "must_go_first": true}, {"variable": "totalresource2", "part": "p1g5", "must_go_first": true}], "maxValue": "best_y", "minValue": "best_y", "variableReplacementStrategy": "alwaysreplace", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}, {"allowFractions": false, "variableReplacements": [{"variable": "best_x", "part": "p3g0", "must_go_first": false}, {"variable": "best_y", "part": "p3g1", "must_go_first": false}], "maxValue": "best_profit", "minValue": "best_profit", "variableReplacementStrategy": "originalfirst", "correctAnswerFraction": false, "showCorrectAnswer": true, "scripts": {}, "marks": 1, "type": "numberentry", "showPrecisionHint": false}], "showCorrectAnswer": true, "scripts": {}, "marks": 0, "type": "gapfill"}], "statement": "

{business_long} ({business_short}) makes two products: {product_1s} and {product_2s}.

\n

Existing orders require {business} to make at least {xconstraint} {product_1s} and {yconstraint} {product_2s} each day.

\n

Each unit of {product_1s} produced uses {resource1x} {resource_1_units} {resource_1} and {resource2x} {resource_2_units} {resource_2}.

\n

Each unit of {product_2s} produced uses {resource1y} {resource_1_units} {resource_1} and {resource2y} {resource_2_units} {resource_2}.

\n

However, the resources are limited: {business} can only obtain {totalresource1} {resource_1_units} {resource_1} and {totalresource2} {resource_2_units} {resource_2} each day.

\n

Each sale of a unit of {product_1s} gives £{profitx} profit. Each sale of a unit of {product_2s} gives £{profity} profit.

", "variable_groups": [{"variables": ["xconstraint", "yconstraint", "resource1x", "resource1y", "resource2x", "resource2y", "r1", "r2", "scalingfactor1", "scalingfactor2", "totalresource1", "totalresource2"], "name": "Constraints"}, {"variables": ["boundx", "boundy", "constraint1xvalue", "constraint1yvalue", "constraint2xvalue", "constraint2yvalue"], "name": "Bounds"}, {"variables": ["profitx", "profity"], "name": "Profit"}, {"variables": ["intersection_points", "possible_points", "profits", "best_point", "best_x_float", "best_y_float", "best_profit_float", "best_x", "best_y", "best_profit", "best_lines", "line_names"], "name": "Optimum strategy"}, {"variables": ["business_long", "business_short", "business", "resource_1", "resource_1_units", "resource_2", "resource_2_units", "product_1", "product_1s", "product_2", "product_2s"], "name": "Text strings"}], "variablesTest": {"maxRuns": 100, "condition": ""}, "variables": {"best_y_float": {"definition": "intersection_points[best_point][1]", "templateType": "anything", "group": "Optimum strategy", "name": "best_y_float", "description": "

The number of units of the second product to produce to earn the highest profit, if fractions are allowed

"}, "best_profit_float": {"definition": "profit(best_x_float,best_y_float)", "templateType": "anything", "group": "Optimum strategy", "name": "best_profit_float", "description": "

The profit at the best intersection point, if fractions of units are allowed

"}, "scalingfactor1": {"definition": "precround((r1+r2)/resource1x,1)", "templateType": "anything", "group": "Constraints", "name": "scalingfactor1", "description": ""}, "scalingfactor2": {"definition": "precround((r1)/resource2x,2)", "templateType": "anything", "group": "Constraints", "name": "scalingfactor2", "description": ""}, "best_y": {"definition": "floor(best_y_float)", "templateType": "anything", "group": "Optimum strategy", "name": "best_y", "description": "

The integer number of units of the second product to produce to earn the highest profit

"}, "best_x": {"definition": "floor(best_x_float)", "templateType": "anything", "group": "Optimum strategy", "name": "best_x", "description": "

The integer number of units of the first product to produce to earn the highest profit

"}, "business_long": {"definition": "\"Amalgamated Mines and Sheep, Inc.\"", "templateType": "string", "group": "Text strings", "name": "business_long", "description": "

The full name of the business

"}, "resource2x": {"definition": "\nrandom(250..450#10)", "templateType": "anything", "group": "Constraints", "name": "resource2x", "description": "

How much of resource 2 the first product uses per unit

"}, "resource2y": {"definition": "\nrandom(1500..3000#100)", "templateType": "anything", "group": "Constraints", "name": "resource2y", "description": "

How much of resource 2 the second product uses per unit

"}, "resource_1_units": {"definition": "\"kg\"", "templateType": "string", "group": "Text strings", "name": "resource_1_units", "description": "

Dimension of the first resource

"}, "yconstraint": {"definition": "random(4..10)", "templateType": "anything", "group": "Constraints", "name": "yconstraint", "description": "

Minimum production of the second product

"}, "constraint2yvalue": {"definition": "r1+yconstraint", "templateType": "anything", "group": "Bounds", "name": "constraint2yvalue", "description": "

Where the constraint line for the second resource cuts the x-constraint.

\n

Second resource line cuts x-constraint at a point greater than the y-constraint

"}, "resource_2": {"definition": "\"iron\"", "templateType": "string", "group": "Text strings", "name": "resource_2", "description": "

The name of the second resource

"}, "resource_1": {"definition": "\"wool\"", "templateType": "string", "group": "Text strings", "name": "resource_1", "description": "

The name of the first resource

"}, "resource_2_units": {"definition": "\"tonnes\"", "templateType": "string", "group": "Text strings", "name": "resource_2_units", "description": "

Dimension of the second resource

"}, "constraint2xvalue": {"definition": "round(scalingfactor2*resource2y+xconstraint)", "templateType": "anything", "group": "Bounds", "name": "constraint2xvalue", "description": "

Where the constraint line for resource 2 cuts the y-constraint

"}, "boundx": {"definition": "max(constraint1xvalue,constraint2xvalue)", "templateType": "anything", "group": "Bounds", "name": "boundx", "description": "

Right bound of the diagram

"}, "product_2s": {"definition": "\"double-edged cardigans\"", "templateType": "string", "group": "Text strings", "name": "product_2s", "description": "

Plural name of the second product

"}, "best_point": {"definition": "best_by(possible_points,profits)", "templateType": "anything", "group": "Optimum strategy", "name": "best_point", "description": "

The index of the valid intersection point with the highest profit

"}, "constraint1xvalue": {"definition": "round(scalingfactor1*resource1y+xconstraint)", "templateType": "anything", "group": "Bounds", "name": "constraint1xvalue", "description": "

Where the constraint line for resource 1 crosses the y-constraint

"}, "business": {"definition": "if(business_short=\"\",business_long,business_short)", "templateType": "anything", "group": "Text strings", "name": "business", "description": ""}, "product_1": {"definition": "\"bulletproof tea cosy\"", "templateType": "string", "group": "Text strings", "name": "product_1", "description": "

Singular name of the first product

"}, "product_2": {"definition": "\"double-edged cardigan\"", "templateType": "string", "group": "Text strings", "name": "product_2", "description": "

Singular name of the second product

"}, "business_short": {"definition": "\"AMS\"", "templateType": "string", "group": "Text strings", "name": "business_short", "description": "

A shorter name for the business, to be repeated throughout the text. If the business name is short enough for repeated use, leave this empty.

"}, "line_names": {"definition": "[ \"the amount of resource 1 used\", \"the amount of resource 2 used\", \"the minimum amount of X produced\", \"the maximum amount of Y produced\" ]", "templateType": "list of strings", "group": "Optimum strategy", "name": "line_names", "description": "

Names of the lines, coded as in the definition of best_lines

"}, "totalresource1": {"definition": "siground(\n scalingfactor1*resource1x*resource1y +\n resource1y*yconstraint +\n resource1x*xconstraint\n,3)", "templateType": "anything", "group": "Constraints", "name": "totalresource1", "description": "

Total amount of resource 1 available

"}, "totalresource2": {"definition": "siground(\n scalingfactor2*resource2x*resource2y +\n resource2y*yconstraint +\n resource2x*xconstraint\n,3)", "templateType": "anything", "group": "Constraints", "name": "totalresource2", "description": "

Total amount of resource 2 available

"}, "best_lines": {"definition": "[[0,2],[1,2],[0,3],[1,3],[0,1]][best_point]", "templateType": "anything", "group": "Optimum strategy", "name": "best_lines", "description": "

Which lines are involed in the best point? Coded as follows:

\n

0 - resource 1

\n

1 - resource 2

\n

2 - minimum x

\n

3 - minimum y

\n

Note that (minimum x,minimum y) is never the best point

"}, "best_x_float": {"definition": "intersection_points[best_point][0]", "templateType": "anything", "group": "Optimum strategy", "name": "best_x_float", "description": "

The number of units of X to produce to earn the highest profit, if fractions are allowed

"}, "r1": {"definition": "random(10..20)", "templateType": "anything", "group": "Constraints", "name": "r1", "description": "

The second constraint line cuts the x-constraint line at this value more than the y-constraint

"}, "r2": {"definition": "random(5..15)", "templateType": "anything", "group": "Constraints", "name": "r2", "description": "

The first constraint line cuts the x-constraint line at this value greater than where the second constraint cuts.

"}, "boundy": {"definition": "max(constraint1yvalue,constraint2yvalue)", "templateType": "anything", "group": "Bounds", "name": "boundy", "description": "

Upper bound of the diagram

"}, "possible_points": {"definition": "filter(\n let(x,floor(intersection_points[j][0]),y,floor(intersection_points[j][1]),\n resource1x*x+resource1y*y <= totalresource1+1 and \n resource2x*x+resource2y*y <= totalresource2+1 and\n x>=xconstraint and\n y>=yconstraint\n ),\n j,\n 0..len(intersection_points)-1\n)", "templateType": "anything", "group": "Optimum strategy", "name": "possible_points", "description": "

Indices of intersection points which satisfy all the constraints.

"}, "resource1y": {"definition": "random(50..70)", "templateType": "anything", "group": "Constraints", "name": "resource1y", "description": "

How much of resource 1 the second product uses per unit

"}, "resource1x": {"definition": "random(20..40)", "templateType": "anything", "group": "Constraints", "name": "resource1x", "description": "

How much of resource 1 the first product uses per unit

"}, "xconstraint": {"definition": "\nrandom(4..10)", "templateType": "anything", "group": "Constraints", "name": "xconstraint", "description": "

Minimum production of the first product

"}, "intersection_points": {"definition": "[\n [xconstraint, (totalresource1-resource1x*xconstraint)/resource1y], //resource 1 intersecting with minimum x\n [xconstraint, (totalresource2-resource2x*xconstraint)/resource2y], //resource 2 intersecting with minimum x\n [(totalresource1-resource1y*yconstraint)/resource1x, yconstraint], //resource 1 intersecting with minimum y\n [(totalresource2-resource2y*yconstraint)/resource2x, yconstraint], //resource 2 intersecting with minimum y\n let(y, (totalresource1-totalresource2*resource1x/resource2x)/(resource1y - resource1x/resource2x * resource2y),\n [(totalresource1-resource1y*y)/resource1x, y] // intersection of the two resource constraints\n )\n]", "templateType": "anything", "group": "Optimum strategy", "name": "intersection_points", "description": "

Intersection points of the constraints - the optimum strategy will be one of these

"}, "best_profit": {"definition": "profit(best_x,best_y)", "templateType": "anything", "group": "Optimum strategy", "name": "best_profit", "description": "

The profit at the best intersection point

"}, "profity": {"definition": "//the coeff of y in the objective function\nceil(profitx*(resource1y/resource1x)*random(1.5..3))", "templateType": "anything", "group": "Profit", "name": "profity", "description": "

Profit for each unit of the second product sold

"}, "profitx": {"definition": "//the coeff of x in the objective function\nrandom(2..4)", "templateType": "anything", "group": "Profit", "name": "profitx", "description": "

Profit for each unit of the first product sold

"}, "product_1s": {"definition": "\"bulletproof tea cosies\"", "templateType": "string", "group": "Text strings", "name": "product_1s", "description": "

Plural name of the first product

"}, "constraint1yvalue": {"definition": "r2+constraint2yvalue", "templateType": "anything", "group": "Bounds", "name": "constraint1yvalue", "description": "

Where line given by resource 1 constraint cuts the x-constraint line.

\n

It is always greater than the point at which the second resource line cuts.

"}, "profits": {"definition": "map(let(x,p[0],y,p[1],profitx*x+profity*y),p,intersection_points)", "templateType": "anything", "group": "Optimum strategy", "name": "profits", "description": "

Profit earned at each intersection point

"}}, "metadata": {"notes": "", "description": "

Student is given a set of constraints for a linear program. Asked to enter the constraints as inequalities, and then to identify the optimal solution.

", "licence": "Creative Commons Attribution 4.0 International"}, "type": "question", "showQuestionGroupNames": false, "question_groups": [{"name": "", "pickingStrategy": "all-ordered", "pickQuestions": 0, "questions": []}], "contributors": [{"name": "Adrian Shepherd", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/811/"}]}]}], "contributors": [{"name": "Adrian Shepherd", "profile_url": "https://numbas.mathcentre.ac.uk/accounts/profile/811/"}]}