JavaScript prevents endless looping - perhaps with a dynamic recognition pattern?

the first one here is the commented pseudo-code:

// TODO: // Person A (80kg) nutrition intake requirements are: // nutrient || Unit(g) // Vitamin A : 30, // Vitamin B1 : 2, // Vitamin C : 300, // Vitamin D : 3000, // Protein : 100, // Calcium : 30 var nutrient_requirements = { vita: {min: 30 ,max: 38}, vitb1: {min:2, max:4}, vitc: {min:300, max: 800}, vitd: {min: 300, max:3000}, protein: {min:100, max:200}, calcium: {min:30, max:50} } // The calculated estimate amount of food // the person eats on a daily base is around 900(g) // The amount will be distributed among the terms // with a predefined pattern var food_amount = { fruits:[200,200], meat: [500] } // START (usefull anchor for this pseudocode) var calculated_nutrition = { vita: 0, vitb1: 0, vitc: 0, vitd: 0, protein: 0, calcium: 0 } // The daily nutrition intake of this person // needs to be achieved by the following terms: // apple, banana, chicken breast // Term nutrient values per gramm var terms = { fruits:[ apple:{ vita: 0.02, vitc: 0.30, vitd: 0.01, protein: 0.08, calcium: 0 }, banana:{ vita: 0.1, vitc: 0.09, vitd: 0.00, protein: 0.1, calcium: 0.2 } ], meat:[ chicken_breast:{ vita: 0.07, vitc: 0.08, vitd: 0.03, protein: 0.4, calcium: 0.2 } ] } // Now we want to see if the normal amount and distribution // of the food covers the required amount // To do that we need to multiply the matching food amount // with the matching food / term and sum up all values for(let prop in terms){ for(let i = 0; i < terms[prop].length; i++){ for(let propb in terms[prop][i]){ calculated_nutrition[propb] = terms[prop][i][propb] * food_amount[prop][i]; } } } // After that is done, we can compare calculated_nutrition to // nutrient_requirements to see whether something is too much // or too little for(let propa in nutrient_requirements){ if(nutrient_requirements[propa].min > calculated_nutrition[propa]){ // this nutrient level is too little // now we need to increase some food / term // in order to achieve the required minimum // of this nutrient alter_amount(propa, "up"); return; }else if(nutrient_requirements[propa].max < calculated_nutrition[propa]){ // this nutrient level is too high // now we need to decrease some food / term // in order to achieve the required minimum alter_amount(propa, "down"); return; }else{ // this nutrient level is ok return; } } function alter_amount(prop, direction){ // here we look in terms which food // has the highest amount of prop switch(direction){ case "down": // here we decrease the amount of // the matching term in the amount object // and re-run this whole calculation from // point START break; case "up": // here we increase the amount of // the matching term in the amount object // and re-run this whole calculation from // point START break; } } 

Let me briefly explain this example.

The calculated expected result is that a person needs to eat X number of apples, number of Y bananas and amount of chicken breast per day per day in order to achieve a daily nutritional goal.

In my pseudo codec, I wrote down the main functions of my program, and the current problem that I am facing is that IF a particular food is ideal for increasing the quantity in one cycle, and then it turns out to be ideal for decreasing the quantity in another cycle - I end an endless cycle.

Based on my minimalistic example, I could firmly point out that if the number of apples increased, it should not decrease in the next cycle, but in my real program I work with a large package of ingredients with a large number of properties. Thus, the difficulty in covering it is tremendously increasing.

I am looking for a way to recognize a pattern that does not produce a result and tells the program to select the second best food to increase or decrease, so as not to end with an endless loop.

Something like this can be avoided:

 apple ++ apple ++ banana ++ apple ++ banana ++ meat -- apple -- apple -- banana -- apple -- banana -- meat ++ apple ++ apple ++ banana ++ apple ++ banana ++ meat -- apple -- apple -- banana -- apple -- banana -- meat ++ ... 

EDIT

The answer below, contributing to the creation of some hashing and storage system, leads to the same result that I experience with my blacklist method.

My blacklist method works as follows:

Apple's amount has been changed (decrement / increment) β†’ keep it blacklisted.

 blacklist = [{product: "apple", altered: "down/up"},...] 

Now everyone in each cycle is scanned before choosing food to increase or decrease the black list. If the perfect fit is in the array, then the second best fit is selected, etc.

There are some additional restrictions, such as: fe Apples can be no more than x% of the total. Or apples can be at least x% of the total.

In a combination of restrictions + blacklisted products, my program ends in a state where it has no more different products to increase or decrease and just does not change anything and ends in an endless cycle without progression

I don’t even know if there is a way to fix this problem programmatically - or if I just say "hey, this problem is not solvable."

All I can think of is a way to implement the functionality that the program recognizes that it is "stuck" β†’ remembers a pattern that leads to a stuck state, and tries to use a different approach again. But this may be redundant in thought.

+5
source share
2 answers

The solution is to remember the set of all the states that you visited before and not to enter the state twice (mark it as β€œtaboo”).

If the state change is small (i.e. if you only change several values), a useful trick is to use zobrist hashing that the hash code for the next state can be calculated in O(n) , where n is the number of changes, not the number of variables .

+3
source

Based on your description, I think that you are dealing with the classic (Unbounded) Knapsack Problem , the purpose of which is to find the best combination (product types) to achieve this measurement (total nutrients). Your pseudo code cannot solve this problem correctly.

There are various parameters for this problem that were not mentioned in the question, for example:

  • What is the weight of each food?
  • Can a single meal exceed a little to achieve better results?
  • How do you decide which combination is better? (How to reduce combos to an account?)
  • When several combos are considered equally good, how do you decide where to go?

You will get less than perfect results if these questions are not answered. When something got worse, you are stuck in an algorithm.

I wrote a fragment to demonstrate a solution to a problem with brute force, using my personal thoughts as answers to the questions above with two foods and two kinds of food.

While the problem space gets complicated very quickly when adding the nutritions / food type, you can always give it various settings to make sure that it can work in a reasonable amount of time in a modern browser.

See JSFiddle . (You might want to turn off line wrapping.)

+1
source

Source: https://habr.com/ru/post/1245923/


All Articles