Fractal Softworks Forum

Please login or register.

Login with username, password and session length
Pages: 1 ... 9 10 [11] 12 13 ... 31

Author Topic: Optimizing the Conquest: a Mathematical Model of Space Combat  (Read 13946 times)

CapnHector

  • Captain
  • ****
  • Posts: 350
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #150 on: November 23, 2022, 10:47:04 PM »

Alright that's great then. Then use that code as it's simpler and let's see the results we get when it's all put together. I must have been missing something very elementary, wouldn't be the first time. Can you just plug the hit probability distribution code into location_probabilities?
« Last Edit: November 23, 2022, 11:11:34 PM by CapnHector »
Logged

intrinsic_parity

  • Admiral
  • *****
  • Posts: 2978
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #151 on: November 24, 2022, 12:16:58 AM »

Yeah, the location_probabilities can come from whatever distribution you want. As long as you have a list of all the possible shot locations and the associated probabilities, everything else is pretty straight forward.

I will say that this way of calculating EV is not perfectly correct for a sequence of shots. I've verified that it's perfectly accurate for one shot. At least, I verified that the expected armor damage of a single shot is accurate to the average damage of one shot over 10k monte carlo trials. There was on the order of 1e-12 error, so basically to within numerical error. I haven't bothered to cook up a test case where hull damage comes into play in one single shot.

But for a sequence of shots, there is decent amount of error due to the fact that you are essentially using the EV of the armor grid from the previous calculation/shot to compute the Ev of the next armor values, which is not strictly correct. I actually went on about this a while back when we were initially discussing distributions. There is a somewhat significant amount of error introduced due to this. In a quick test case with 10000 hull and 1000 armor vs 400 energy damage, the error between the expected hull values and the average hull from 10k monte carlo runs maxed out at a few hundred hull points. So on the order of 5% error. The number of shots to kill though was fairly close and stable.

Edit: forgot to mention this is all for a pretty wide uniform distribution of shots because I am lazy and just wanted to test things. Not sure how different distributions will change things. A very quick test found that the magnitude of the error seemed to decrease approximately proportionally with the width of the uniform distribution, so as the shots get tighter, there is less error.

Some fun plots to highlight this:
Spoiler




You can see in the first figure that the dark black line (the EV) is somewhat off from the average of the red dashed lines (the MC trials). In the second figure, I plotted the error between the EV and the average of the MC trials.
[close]
« Last Edit: November 24, 2022, 12:22:28 AM by intrinsic_parity »
Logged

CapnHector

  • Captain
  • ****
  • Posts: 350
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #152 on: November 24, 2022, 01:18:13 AM »

If you think this is correct:


and we have a wide uniform distribution, then the calculation for the aggregate exact expected value becomes pretty easy as p_1=p_2=p_3...=p_n and then sum_j sum_i D_ij A_ij is exactly equivalent to p*sum_j sum_i X_ij, so if you have a wide uniform distribution then it is equivalent to calculating it in aggregate at the midpoint of each cell and then distributing the damage. Likewise if you have an extremely narrow distribution then for some k you would have p_1=p_2=...=p_{k-1}=p_{k+1}=...=p_n=0 and p_k = 1. And then you get sum_j sum_i D_ij A_ij = sum_j sum_i A_ij when the middle cell is k so the damage around middle cell k is accurate to calculate in aggregate and then distribute (for the first shot, anyway). The problem is specifically the arbitrary case of non-trivial probability distributions and arbitrary locations on the armor.

However, if it's a small error, then of course it might be reasonable to just ignore it. On the other hand the cell by cell calculation I posted above seems to do it fast too and computes the above matrix thing.

Well, it's probably going to be fine either way based on your simulations so just implement one way and fix if needed.

Incidentally here is the error of this


We should also be able to set some upper bounds on epsilon but I didn't post it as I'm a little uncertain on it but it appears it is small? (from



and noting that at least K_ij > 0 in this case, (h/(x+h))''=2h/(x+h)^3 and sigma^2 is less than (A_ij/2)^2 - I'll admit to being out of my depth here for the time being so anybody who knows this stuff, chime in. Numerically I tried setting A_ij ~ N(a/30, (a/30)^2) (ie armor is almost completely random) with an upper bound of a/30 and lower bound of 0, and I found that running hit strength from 10 to 1000 in increments of 10 and ship armor from 0 to 1750 in increments of 50, then with 100 samples from each combination of armor and hit strength the maximum upper bound for epsilon in the worst case scenario (as max(sigma^2(h/(x+h)''/2)) observed in the dataset was 0.0658 and the average upper bound for epsilon was 0.0028 (ie model underestimates real expected value damage between arbitrary consecutive timepoints by at most 0.28% on average, but with a particularly crude worst-case estimation of the upper bound).


« Last Edit: November 24, 2022, 05:54:58 AM by CapnHector »
Logged

Liral

  • Admiral
  • *****
  • Posts: 529
  • Realistic Combat Mod Author
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #153 on: November 24, 2022, 07:44:58 AM »

Thanks for confirming, CapnHector.  I hope this code reflects my understanding accurately.

import numpy as np

PADDING = 2

MAXIMUM_DAMAGE_REDUCTION = 0.85

MINIMUM_ARMOR_FACTOR = 0.05

POOLING_FACTORS = np.array([
    [0.0, 0.5, 0.5, 0.5, 0.0],
    [0.5, 1.0, 1.0, 1.0, 0.5],
    [0.5, 1.0, 1.0, 1.0, 0.5],
    [0.5, 1.0, 1.0, 1.0, 0.5],
    [0.0, 0.5, 0.5, 0.5, 0.0]
])


def padded_grid(row_width):
    """
    Return a padded grid around a row of some width.
    """
    grid_width = row_width + 2 * PADDING
    grid_height = 1 + 2 * PADDING
    #cell_ids are just so you, the reader, can tell the cells apart
    #I will replace them with armor_rating / 15
    cell_ids = np.arange(grid_width * grid_height, dtype = 'float64')
    return np.reshape(cell_ids, (grid_width, grid_height))


def square_grids(padded_grid):
    """
    Return one square grid for each cell along the middle
    row of a padded grid, less the padding to either side.
    """
    return np.array([padded_grid[i - PADDING - 1 : i + PADDING] for i in
                    range(PADDING + 1, len(padded_grid) - 1)])


def pool(armor_grids):
    """
    Return the pooled armor value of the cells of each
    of several armor grids.
    """
    return np.array([np.sum(POOLING_FACTORS * grid) for grid in armor_grids])


def armor_damage_factor(hit_strength, pooled_armor):
    """
    Return the factor multiplying the damage of a hit to
    armor cells.
    """
    damage_factor = hit_strength / (hit_strength + pooled_armor)
    damage_factor[np.less(MAXIMUM_DAMAGE_REDUCTION, damage_factor)] = (
        MAXIMUM_DAMAGE_REDUCTION)
    return damage_factor
   
   
def hull_damage_factor(hit_strength, pooled_armor, armor_rating):
    """
    Return the factor multiplying the damage of a hit to
    the hitpoints of a ship.
    """
    pooled_armor[np.less(pooled_armor, armor_rating * MINIMUM_ARMOR_FACTOR)] = (
        armor_rating * MINIMUM_ARMOR_FACTOR)
    return hit_strength / (hit_strength + pooled_armor)


def armor_damage(hit_strength, pooled_armor):
    """
    Return the maximum damage to a hit inflicts upon
    cells of a pooled armor value.
    """
    return hit_strength * armor_damage_factor(hit_strength, pooled_armor)
   
   
def hull_damage(hit_strength, pooled_armor, armor_rating):
    """
    Return the damage a hit inflicts upon the hitpoints of a ship.
    """
    return hit_strength * hull_damage_factor(hit_strength, pooled_armor,
                                            armor_rating)


def main():
    """
    Demonstrate the above functions.
    """
    #target
    hull = 1000
    armor_rating = 500
    armor_per_cell = 100
    armor_row_width = 10
   
    #shooter
    hit_probabilities = np.array([0.1 for _ in range(armor_row_width)])
    hit_strength = 100
   
    armor_row = np.full(armor_row_width, armor_per_cell)
    print("armor row")
    print(armor_row, "\n")
   
    armor_grid = padded_grid(armor_row_width)
    print("armor grid")
    print(armor_grid, "\n")
   
    virtual_armor_grids = square_grids(armor_grid)
    print("virtual armor grids")
    print(virtual_armor_grids,"\n")

    pooled_armor = pool(virtual_armor_grids)
    print("pooled armor")
    print(pooled_armor, "\n")
   
    damage_to_armor = armor_damage(hit_strength, pooled_armor)
    print("damage to armor")
    print(damage_to_armor, "\n")
   
    damage_to_hull = hull_damage(hit_strength, pooled_armor, armor_rating)
    print("damage to hull")
    print(damage_to_hull, "\n")
   
main()
output
armor row
[100 100 100 100 100 100 100 100 100 100]

armor grid
[[ 0.  1.  2.  3.  4.]
 [ 5.  6.  7.  8.  9.]
 [10. 11. 12. 13. 14.]
 [15. 16. 17. 18. 19.]
 [20. 21. 22. 23. 24.]
 [25. 26. 27. 28. 29.]
 [30. 31. 32. 33. 34.]
 [35. 36. 37. 38. 39.]
 [40. 41. 42. 43. 44.]
 [45. 46. 47. 48. 49.]
 [50. 51. 52. 53. 54.]
 [55. 56. 57. 58. 59.]
 [60. 61. 62. 63. 64.]
 [65. 66. 67. 68. 69.]]

virtual armor grids
[[[ 0.  1.  2.  3.  4.]
  [ 5.  6.  7.  8.  9.]
  [10. 11. 12. 13. 14.]
  [15. 16. 17. 18. 19.]
  [20. 21. 22. 23. 24.]]

 [[ 5.  6.  7.  8.  9.]
  [10. 11. 12. 13. 14.]
  [15. 16. 17. 18. 19.]
  [20. 21. 22. 23. 24.]
  [25. 26. 27. 28. 29.]]

 [[10. 11. 12. 13. 14.]
  [15. 16. 17. 18. 19.]
  [20. 21. 22. 23. 24.]
  [25. 26. 27. 28. 29.]
  [30. 31. 32. 33. 34.]]

 [[15. 16. 17. 18. 19.]
  [20. 21. 22. 23. 24.]
  [25. 26. 27. 28. 29.]
  [30. 31. 32. 33. 34.]
  [35. 36. 37. 38. 39.]]

 [[20. 21. 22. 23. 24.]
  [25. 26. 27. 28. 29.]
  [30. 31. 32. 33. 34.]
  [35. 36. 37. 38. 39.]
  [40. 41. 42. 43. 44.]]

 [[25. 26. 27. 28. 29.]
  [30. 31. 32. 33. 34.]
  [35. 36. 37. 38. 39.]
  [40. 41. 42. 43. 44.]
  [45. 46. 47. 48. 49.]]

 [[30. 31. 32. 33. 34.]
  [35. 36. 37. 38. 39.]
  [40. 41. 42. 43. 44.]
  [45. 46. 47. 48. 49.]
  [50. 51. 52. 53. 54.]]

 [[35. 36. 37. 38. 39.]
  [40. 41. 42. 43. 44.]
  [45. 46. 47. 48. 49.]
  [50. 51. 52. 53. 54.]
  [55. 56. 57. 58. 59.]]

 [[40. 41. 42. 43. 44.]
  [45. 46. 47. 48. 49.]
  [50. 51. 52. 53. 54.]
  [55. 56. 57. 58. 59.]
  [60. 61. 62. 63. 64.]]

 [[45. 46. 47. 48. 49.]
  [50. 51. 52. 53. 54.]
  [55. 56. 57. 58. 59.]
  [60. 61. 62. 63. 64.]
  [65. 66. 67. 68. 69.]]]

pooled armor
[180. 255. 330. 405. 480. 555. 630. 705. 780. 855.]

damage to armor
[35.71428571 28.16901408 23.25581395 19.8019802  17.24137931 15.26717557
 13.69863014 12.42236025 11.36363636 10.47120419]

damage to hull
[35.71428571 28.16901408 23.25581395 19.8019802  17.24137931 15.26717557
 13.69863014 12.42236025 11.36363636 10.47120419]

« Last Edit: November 24, 2022, 07:49:38 AM by Liral »
Logged

CapnHector

  • Captain
  • ****
  • Posts: 350
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #154 on: November 24, 2022, 08:27:38 AM »

Well, a big issue is I can't really read the code. But it seems like what you are doing is pooling the armor, which you shouldn't do if you go cell by cell as I argued above and the C++ function of mine that gave the correct result doesnt. Apologies, it seemed so plausible you should that I got sucked in, wrote it wrong and got obviously wrong results, and retracted and wrote the latex to show why.

Essentially I suggest you pre-compute the matrix D that I described above in the latex posts (this seems complicated maybe but it's actually just what we started with when I first did this, do overlapping sums of the pooling factors matrix multiplied by probability to hit center cell over the padded matrix) and then just go cell by cell so you assign damage and hit strength multiplied by the matrix D for each cell. No pooling and no distributing as those are included in the matrix. The error should be small like calculated and this removes the inaccuracy from pooling without adjusting for probability.

(The exact calculation that should be performed for each cell is in the latex after [C_ij]=...)

And then hull damage comes from each cell the usual way, min(0, damage -max(armor,minarmor)) adjusted for modifier again without any pooling.

Here is the algorithm in plain English
1. Compute the damage distribution matrix. Ie: create a matrix padded with 2 cells in each direction around the ship 's cells that are in a line. Set it to 0.
2. To this matrix sum: for each of the central cells, sum the 5*5 pooling matrix (0, 1/30, 1/30, 1/30, 0\\ 1/30, 1/15... one) multiplied by probability to hit the cell, centered at that cell. This is the damage distribution matrix D and it must be calculated separately for all probability distributions.
3. Now initialize the ship's armor as a matrix of the same size filled with 1/15 of ship armor. Preparations done.

To damage cells:
For each cell of the armor matrix, calculate armor hit strength reduction as shot hit strength / (shot hit strength + armor value in cell) (no pooling). Apply the minimum armor rule here for when cell armor hp is less than 5%. Deal to the cell amount of damage that is full shot damage * the armor reduction you calculated in the previous step * value in matrix D at that same location, adjusting for maximum armor damage reduction. If the damage dealt is more than the armor hp, then also deal hull damage, which is the difference. Note that this description does not include modifiers, but include them in all parts of the calculation including for hit strength, for damage to armor and for hull damage. For hit strength and damage to armor use the modifier vs armor and re-scale back to raw damage for the hull damage. Also make sure armor doesn't go below zero so set it back to 0 as necessary.


This works because pooling is included in D_ij and the above algorithm does it appropriately. So that's it. It's much easier to write in code than justify mathematically or explain and it produces the correct result.

Edit: added a missing point about*armor reduction
« Last Edit: November 24, 2022, 09:20:19 AM by CapnHector »
Logged

Liral

  • Admiral
  • *****
  • Posts: 529
  • Realistic Combat Mod Author
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #155 on: November 24, 2022, 09:35:08 AM »

Well, a big issue is I can't really read the code. But it seems like what you are doing is pooling the armor, which you shouldn't do if you go cell by cell as I argued above and the C++ function of mine that gave the correct result doesnt. Apologies, it seemed so plausible you should that I got sucked in, wrote it wrong and got obviously wrong results, and retracted and wrote the latex to show why.

Wait, you retracted armor pooling?  I can't find it. :(  I admit I haven't been reading as closely as I perhaps should have because you (as I do) often change your post after making it or later post another one correcting what you wrote.  I've been waiting for you to settle down on your best idea. :D

Quote
Essentially I suggest you pre-compute the matrix D that I described above in the latex posts (this seems complicated maybe but it's actually just what we started with when I first did this, do overlapping sums of the pooling factors matrix multiplied by probability to hit center cell over the padded matrix) and then just go cell by cell so you assign damage and hit strength multiplied by the matrix D for each cell. No pooling and no distributing as those are included in the matrix. The error should be small like calculated and this removes the inaccuracy from pooling without adjusting for probability.

(The exact calculation that should be performed for each cell is in the latex after [C_ij]=...)

And then hull damage comes from each cell the usual way, min(0, damage -max(armor,minarmor)) adjusted for modifier again without any pooling.

Here is the algorithm in plain English

I will try to step through this algorithm by hand for a row that is five cells wide, an armor rating of 150, and hit strength of 10.

Quote
1. Compute the damage distribution matrix. Ie: create a matrix padded with 2 cells in each direction around the ship 's cells that are in a line. Set it to 0.

row
10 10 10
damage distribution matrix
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0


Quote
2. To this matrix sum: for each of the central cells, sum the 5*5 pooling matrix (0, 1/30, 1/30, 1/30, 0\\ 1/30, 1/15... one) multiplied by probability to hit the cell, centered at that cell. This is the damage distribution matrix D and it must be calculated separately for all probability distributions.

I don't know exactly what this means but will guess. Also, why are we applying probability before the damage distribution?  Should we not do some sort of complicated average later instead?  I wonder if it'd be equivalent, ultimately.  Anyhow...

pooling matrix
0    1/30 1/30 1/30 0     
1/30 1/15 1/15 1/15 1/30
1/30 1/15 1/15 1/15 1/30
1/30 1/15 1/15 1/15 1/30
0    1/30 1/30 1/30 0     
sum of pooling matrix
9/15 + 12/30 = 9/15 + 6/15 = 15/15 = 1
probabilities times sum
[p1, p2, p3] * 1 = [p1 * 1, p2 * 1, p3 * 1] = [p1, p2, p3]
Surely this isn't what you meant. 

Quote
3. Now initialize the ship's armor as a matrix of the same size filled with 1/15 of ship armor. Preparations done.

Of what size, exactly?  Row padded on all four sides?

150 ship armor rating / 15th of armor rating per cell = 10 armor per cell

ship armor
10 10 10 10 10 10 10
10 10 10 10 10 10 10
10 10 10 10 10 10 10
10 10 10 10 10 10 10
10 10 10 10 10 10 10


Quote
To damage cells:
For each cell of the armor matrix, calculate armor hit strength reduction as shot hit strength / (shot hit strength + armor value in cell) (no pooling).

10 hit strength / (10 hit strength + 10 armor in cell) = 1/2 hit strength factor

1/2 1/2 1/2 1/2 1/2 1/2 1/2
1/2 1/2 1/2 1/2 1/2 1/2 1/2
1/2 1/2 1/2 1/2 1/2 1/2 1/2
1/2 1/2 1/2 1/2 1/2 1/2 1/2
1/2 1/2 1/2 1/2 1/2 1/2 1/2


Quote
Apply the minimum armor rule here for when cell armor hp is less than 5%.

Wait, isn't that just for hull damage calculation?

Quote
Deal to the cell amount of damage that is full shot damage * value in matrix D at that same location, adjusting for maximum armor damage reduction.

If the damage dealt is more than the armor hp, then also deal hull damage, which is the difference. Note that this description does not include modifiers, but include them in all parts of the calculation including for hit strength, for damage to armor and for hull damage. For hit strength and damage to armor use the modifier vs armor and re-scale back to raw damage for the hull damage. Also make sure armor doesn't go below zero so set it back to 0 as necessary.

I'm lost at this point because of problems before. :(

Quote
This works because pooling is included in D_ij and the above algorithm does it appropriately. So that's it. It's much easier to write in code than justify mathematically or explain and it produces the correct result.

Edit: added a missing point about*armor reduction

Then write it in code, perhaps pure C++? :)  I would happily translate it to NumPy.
« Last Edit: November 24, 2022, 09:45:01 AM by Liral »
Logged

CapnHector

  • Captain
  • ****
  • Posts: 350
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #156 on: November 24, 2022, 09:43:09 AM »

Ok if the minimum armor rule is not applied for hit strength (I did not know this) then ignore that part. More shortly. Sorry I'm typing in short bursts again

- here's what it looks like from the previous code:

# this is the default distribution of damage to armor cells
b <- matrix(0,nrow=5,ncol=5)
b[1:5,2:4] <- 1/30
b[2:4,1:5] <- 1/30
b[2:4,2:4] <- 1/15
b[1,1] <- 0
b[1,5] <- 0
b[5,1] <- 0
b[5,5] <- 0

#this function generates a sum of matrices multiplied by the distribution

createhitmatrix <- function(acc){
  hitmatrix <- matrix(0,5,ship[6]+4)
  distributionvector <- createdistribution(acc)
  for (i in 1:ship[6]){
    hitmatrix[,i:(i+4)] <- hitmatrix[,i:(i+4)]+b*(distributionvector[i+1])
  }
  return(hitmatrix)
}

The code I posted above contains a fully working example. I'll re post it next message.

Here is an example of the D matrix from a ship with 2 armor cells with SD = 50 and spread = 0


> weapon1[[8]]
[[1]]
           [,1]       [,2]       [,3]       [,4]       [,5]       [,6]
[1,] 0.00000000 0.01620322 0.03240644 0.03240644 0.01620322 0.00000000
[2,] 0.01620322 0.04860966 0.06481287 0.06481287 0.04860966 0.01620322
[3,] 0.01620322 0.04860966 0.06481287 0.06481287 0.04860966 0.01620322
[4,] 0.01620322 0.04860966 0.06481287 0.06481287 0.04860966 0.01620322
[5,] 0.00000000 0.01620322 0.03240644 0.03240644 0.01620322 0.00000000
« Last Edit: November 24, 2022, 09:52:37 AM by CapnHector »
Logged

intrinsic_parity

  • Admiral
  • *****
  • Posts: 2978
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #157 on: November 24, 2022, 09:55:35 AM »

Not gonna lie, your notation is very terse and I haven't felt like figuring it out in detail until now lamo.

Looking at it more closely, I find it really odd that D matrix, including probabilities, is going into the armor damage reduction. I don't think those probabilities should be appearing in the h/(h + a) expression. Probability should not be passed through the non-linear function. They just multiply the results.

Also, I don't really understand why h is being multiplied by the D array either? only armor should be multiplied by it.

The correct armor damage multiplier considering pooling should be something like hit_strength/(hit_strength + sum(wij*aij)) where wij are the associated weights for inner and outer cells.

Overall, I think the main difference in our approaches, is that you are trying to loop through the armor cells and calculate each one individually, and then handle the different possibilities of shot locations inside those expressions. What I am doing is looping through the shot locations with outer loop and then accounting for all the cells affected by that shot location in an inner loop (which is actually vectorized). My approach is very convenient because the armor pooling calculations and damage distribution are a function of the shot location, so it's very easy to code.
« Last Edit: November 24, 2022, 09:57:49 AM by intrinsic_parity »
Logged

CapnHector

  • Captain
  • ****
  • Posts: 350
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #158 on: November 24, 2022, 09:56:33 AM »

Attached to this message is a fully functioning copy in R and the RCpp code.

Replies
Quote
s I perhaps should have because you (as I do) often change your post after making it or later post another one correcting what you wrote.  I've been waiting for you to settle down on your best idea

Yeah sorry it's a side effect of writing in 5 minute bursts while doing other stuff, I told you about my schedule earlier and that wasn't even all

Quote
Also, why are we applying probability before the damage distribution?  Should we not do some sort of complicated average later instead? 

Exact same thing. You would end up with the matrix D from the latex. This is a convenient way of contributing it. In a sum and product operation the order doesn't matter.

Quote
Of what size, exactly?  Row padded on all four sides?
5 x shipcells + 4

Liral

  • Admiral
  • *****
  • Posts: 529
  • Realistic Combat Mod Author
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #159 on: November 24, 2022, 10:01:24 AM »

Attached to this message is a fully functioning copy in R and the RCpp code.

Ok, so is this it?  If so, I will start translating to Python.  :)

intrinsic_parity

  • Admiral
  • *****
  • Posts: 2978
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #160 on: November 24, 2022, 10:11:08 AM »

You definitely can't not do armor pooling. If you aren't doing it, something is wrong. The pooled armor goes through the non-linear armor damage multiplier, so you have to do it, I'm pretty sure.

I think your Xij expression is wrong. Or more precisely, not equivalent to what happens in the game.
« Last Edit: November 24, 2022, 10:13:23 AM by intrinsic_parity »
Logged

CapnHector

  • Captain
  • ****
  • Posts: 350
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #161 on: November 24, 2022, 10:20:12 AM »

Not gonna lie, your notation is very terse and I haven't felt like figuring it out in detail until now lamo.

What? Based on peer grading in my maths program I thought I was one of the most verbal  :D

As for the lack of pooling then basically the idea is just that you must either pool armor - which is non-trivial due to what was said above - or distribute damage and compare hit strength locally.

I'm.not going to argue that it is complicated and weird and possibly wrong in some way, it's just the best I could come up with, so just show your method works for arbitrary probability distributions (or ok, convolutions of uniform and normal distributions) and arbitrary weapon combos and you likely have yourself two converts. Since Liral is writing modular code this should be fixable later if there's a better idea, anyway.

CapnHector

  • Captain
  • ****
  • Posts: 350
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #162 on: November 24, 2022, 10:22:54 AM »

Attached to this message is a fully functioning copy in R and the RCpp code.

Ok, so is this it?  If so, I will start translating to Python.  :)

That's the one to produce graphs. It would probably be smart to make a similar thing in Python to produce graphs, so we can try combos of weapons vs eg the old or Vanshilars or new experimental data to make sure results are sane, before proceeding to the optimization.

intrinsic_parity

  • Admiral
  • *****
  • Posts: 2978
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #163 on: November 24, 2022, 10:28:02 AM »

Liral, did you see the python code I posted a little earlier? Pretty sure that is correct unless you can find some errors. It is based on code that matched other results previously.

CapnHector, it looks like your armor calculation for an armor cell only use the value of that same armor cell. That sort of defeats the purpose of the armor gird. The whole idea is that adjacent cells are contributing armor? I don't really see the point in using something that is 'weird and possibly wrong in some way' when there is code that (I think) is correct?
Logged

Thaago

  • Global Moderator
  • Admiral
  • *****
  • Posts: 6660
  • Harpoon Affectionado
    • View Profile
Re: Optimizing the Conquest: a Mathematical Model of Space Combat
« Reply #164 on: November 24, 2022, 10:34:19 AM »

@intrinsic_parity

Nice code! Very readable and clear which is always the most important thing in code when getting it working/checking it. In terms of optimizations I see a few things that should help but will reduce readability. In particular, avoiding instantiating new arrays when possible should give a large performance boost.

The first that pops out to me is that the getArmorIndexes is instantiating 2 new arrays each time it is run, but this is never used in parallel IE its never needed for 2 different sets of masks to exist at the same time. So, if an array for inner_cells and outer_cells is instantiated once externally, then passed as arguments into this function, that could be avoided... of course now the code has to keep python's referencing scheme really solidly in mind or its going to have odd bugs, and also needs to be careful about only using 'in place' operations which can be nasty if you aren't used to it because of python's opaque passing model.

For in place operations, probably the most helpful thing is that all of the +=, *=, etc operations are by default in place, so using them is 'safe'. For boolean operations using += and *= can change the data type to int by accident, but using the bitwise operators &= and |= are safe. |=True will flip elements to True, while &=False will flip elements to False. There is also numpy.copyto, which is in place and also accepts an optional mask! Seems perfect for later work if the base operations are too clunky.

It's easy enough in python to do accidental initializations that I'd want to do comparative unit tests between and final code and a equivalent but deliberately re-initializing code to make sure there is a time difference. Kind of blarf, optimization sucks!

As you pointed out armor_grid.shape doesn't change, so can be precomputed and passed as an argument, though its probably not costing very much. The bounds checking can be commented out for a "production" run or put on an if debug==True statement.

'damage_armor' is similarly a new array, but only one is ever used in the calculations at a time, so can be externalized and only modified in place instead of instantiated (again with *=, += etc functions).

'damage_hull' in armor_update doesn't need to be instantiated at all as an array as every operation on it is elementwise and its not returned. I think
Code
damage_hull_total = np.sum(np.maximum(damage_armor - armor_grid, 0) * dmg[2] / dmg[1])
Will do the truck because numpy should detect that every function is elementwise... but I'd want to test to be sure and I could be wrong there.

There are probably other small things, but this is the thing that pops out to me!
Logged
Pages: 1 ... 9 10 [11] 12 13 ... 31