List all possible combinations of variables with factors - python

So I am trying to think of how I can list all possible combinations of 5 variables (that have a set value AND a second property, like a charge for example, so for example I would have x = 100 and has a charge state of +1) with different factors to each variable (so x can vary between 1 and 4, y only between 1 and 2).
At the end I would like to have a list with the combination of variables and the summed value of all like this:
4x+2y+3*z = 1400 (3+)
Is this possible? I am trying to wrap my head around this or if there are too many variables in this.
I am a beginner, so explain it like I am dumb.
Thx

Related

Pyomo: a Set of a Set

I'm new to Pyomo and Python. I was wondering if someone could help me with the case of a Set Q that is based on a Set P.
model.P = pyo.Set(initialize=list(df.iloc[:,0]))
model.Q = pyo.Set(model.P)
Model.P stands for the products I read in out of a file. Model.Q is the number of possible quantities for every product.
So, for example: product "AAA" has 3 different quantities, than I would like to set model.Q["AAA"] equal to the range(1,3). Product "BBB" has 7 different quantities, than I would like to set model.Q["BBB"] equal to the range(1,7).
The number of quantities are read into a list [3, 7, ...]
When I want to initialize a parameter like the following, it gives an error like below the example.
# Setup time
model.st = pyo.Param(model.P,model.Q,initialize=setupTimes,domain=pyo.NonNegativeReals)
TypeError: Cannot apply a Set operator to an indexed Set component (Q)
How can I implement this? Thanks for the help.
I really do not know what you intend to do with that set, but I feel there may be other ways to efficiently model your problem with just a set and a parameter of quantities for each set.
However, to do what you want, one way I suggest is to create a second set "model.PP" which has the range(max(list)) as elements.
Then you create a list of tuples mapping each of model.P to the elements of model.PP appropriately which you then use to initilise model.Q ie.
model.Q = pyo.Set(within=model.P*model.PP, initialise=[("AAA",1), ("AAA",2). . .])
You can create that new list with a for loop.

List's and while loops - Python

I am fairly new to Python and I am stuck on a particular question and I thought i'd ask you guys.
The following contains my code so far, aswell as the questions that lie therein:
list=[100,20,30,40 etc...]
Just a list with different numeric values representing an objects weight in grams.
object=0
while len(list)>0:
list_caluclation=list.pop(0)
print(object number:",(object),"evaluates to")
What i want to do next is evaluate the items in the list. So that if we go with index[0], we have a list value of 100. THen i want to separate this into smaller pieces like, for a 100 gram object, one would split it into five 20 gram units. If the value being split up was 35, then it would be one 20 gram unit, on 10 gram unit and one 5 gram unit.
The five units i want to split into are: 20, 10, 5, 1 and 0.5.
If anyone has a quick tip regarding my issue, it would be much appreciated.
Regards
You should think about solving this for a single number first. So what you essentially want to do is split up a number into a partition of known components. This is also known as the Change-making problem. You can choose a greedy algorithm for this that always takes the largest component size as long as it’s still possible:
units = [20, 10, 5, 1, 0.5]
def change (number):
counts = {}
for unit in units:
count, number = divmod(number, unit)
counts[unit] = count
return counts
So this will return a dictionary that maps from each unit to the count of that unit required to get to the target number.
You just need to call that function for each item in your original list.
One way you could do it with a double for loop. The outer loop would be the numbers you input and the inner loop would be the values you want to evaluate (ie [20,10,5,1,0.5]). For each iteration of the inner loop, find how many times the value goes into the number (using the floor method), and then use the modulo operator to reassign the number to be the remainder. On each loop you can have it print out the info that you want :) Im not sure exactly what kind of output you're looking for, but I hope this helps!
Ex:
import math
myList=[100,20,30,40,35]
values=[20,10,5,1,0.5]
for i in myList:
print(str(i)+" evaluates to: ")
for num in values:
evaluation=math.floor(i/num)
print("\t"+str(num)+"'s: "+str(evaluation))
i%=num

python insert into list at constant x position

I know by the title this may sound easy. It's not for this task.
Imagine the following scenerio: you have a connection running, and a list called example. You get some data with a constant number x that will always start with 1 and increase then on until the connection is closed. You need some data surrounding this number and it to be stored in a list at exactly that number's position. so example[x-1]. Ok, so this solves the basic problem.
The problem this doesn't solve is, say if that the connection gives you a command to delete some of the data previously stored as it's no longer needed. Let's say at this point, you have 10 item's in the list, you need to delete at positions 3, 5, and 6. So now, example is at 7. x is now 11, you insert some data, and now example's length is at 8. At this point, exmaple[x-1] != 11. So now, we have fragmentation.
The problem is this. The connection will (but not in a set order) give you some other data. This data will also have the same number as x, but we'll say it's y. This data need's to go together (let's just say x and y are int's that need to be added for purposes of this example, though we're really filling in missing stuff in a class). but at a later point in the data sequence, but you now no longer have x-1 to put the 2 parts of data together. The problem now is that because you're not able to set example[x] and ALWAYS have it EXACTLY at position x in example, there's now no way in run-time to match both positions x and y.
My question is, is there some way like in C++ how you can do example[x] = data; and it will always be no matter what in position x dependent on what's changed around in the list, such as removing items. If this isn't possible, then I'll put efforts into calculating a formula for the position of the example list so that it can always match.
example = {}
example[1] = "whatever"
example[99] = "whatever"
example[-12] = "something else"
example['cow'] = 'pie'
#delete
example.pop(99)
is that what you are looking for?
or
example = [0 for _ in range(MAX_ITEMS)]
#delete
example[x-1] = 0
#add
example[x-1] = data

Plotting occurrences for values higher than a threshold in Python

I have a non-uniform array 'A'.
A = [1,3,2,4,..., 12002, 13242, ...]
I want to explore how many elements from the array 'A' have values above certain threshold values.
For example, there are 1000 elements that have values larger than 1200, so I want to plot the number of elements that have values larger than 1200. Also, there are other 1500 elements that have values larger than 110 (this includes the 1000 elements, whose values are larger than 1200).
This is a rather large data set, so I would not like to omit any kind of information.
Then, I want to plot the number of elements 'N' above a value A vs. Log (A), i.e.
**'Log N(> A)" vs. 'Log (A)'**.
I thought of binning the data, but I was rather unsuccessful.
I haven't done that much statistics in python, so I was wondering if there is a good way to plot this data?
Thanks in advance.
Let me take another crack at what we have:
A = [1, 3, 2, 4, ..., 12002, 13242, ...]
# This is a List of 12,000 zeros.
num_above = [0]*(12000)
# Notice how we can re-write this for-loop!
for i in B:
num_above = [val+1 if key <= i else val for key,val in enumerate(num_above)]
I believe this is what you want. The final list num_above will be such that for num_above[5] equals the number of elements in A that are above 5.
Explanation::
That last line is where all the magic happens. It goes through elements in A (i)and adds one to all the elements in num_above whose index is less than i.
The enumerate(A) statement is an enumerator that generates an iterator of tuples that include the keys and values of all the elements in A: (0,1) (1,3) -> (2,2) -> (3,4) -> ...
Also, the num_above = [x for y in List] statement is known as List Comprehension, and is a really powerful tool in Python.
Improvements: I see you already modified your question to include these changes, but I think they were important.
I removed the numpy dependency. When possible, removing dependencies reduces the complexity of projects, especially larger projects.
I also removed the original list A. This could be replaced with something that was basically like A = range(12000).

How to create values from Zipf Distribution with range n in Python?

I would like to create an array of Zipf Distributed values withing range of [0, 1000].
I am using numpy.random.zipf to create the values but I cannot create them within the range I want.
How can I do that?
normalize and multiply by 1000 ?
a=2
s = np.random.zipf(a, 1000)
result = (s/float(max(s)))*1000
print min(s), max(s)
print min(result), max(result)
althought isn't the whole point of zipf that the range of values is a function of the number of values generated ?
I agree with the original answer (Felix) that forcing Zipf values to a specific range is a very unusual thing, and it likely means that you're doing something wrong.
Having said that, I actually had a similar problem, where I really did need to generate Zipf values conforming to a certain criteria. In my case, I wanted to generate a brand new set of data that was similar to an existing data set. I wanted the sum to be the same as the existing distribution, but the values to be different.
My insight is that it's possible to re-generate the values a few times until you get ones you like.
#Generate a quantity of Zipf-distributed values close to a desired sum
def gen_zipf_values(alpha, sum, quantity):
best = []
best_sum = 0
for _ in range(10):
s = np.random.zipf(alpha,quantity)
this_sum = s.sum()
if (this_sum > best_sum) and (this_sum <= sum):
best = s
best_sum=this_sum
return best
Again, this solution is tailored to my problem, where I wanted to generate values close to a sum, without going over. I also had a pretty good idea of what I wanted alpha to be in each time. I omitted some of the conditions checking, sorting, etc. for clarity.
If you had to do it more than a few times though (i.e. you had to run the for loop 1 million times to get your distribution), you probably have something wrong (like alpha, or unrealistic expectations on the values). I feel it's valid to 'let the computer do the work', or to hand-pick the best option from a few reasonable ones.

Categories

Resources