(posted for reference)

**Research: Reforging and Stat Weights (non-Rune)**
**Motivation**
I often see "Agility > Master > Crit > etc..." posted, but there rarely is an explanation concerning it's origin. It's actually like this for many classes/specs, for PvP or PvE, low or high item-level, somewhere someone established what the relative priority was and converted it into "A > B > C". However, a good rule of thumb for gaming (or competition in general):

-- don't assume the common answer as correct;

-- in addition to reading others' research -- do your own;

-- and understand the origins and methodology.

**The Foundation**
Imagine you have the choice of two different flasks: +1000 Agility and +1000 Mastery -- which is better? Well let's pick one flask (Agility) and beat on a target dummy for a while, then swap to other flask (Mastery) and beat on the target dummy again. Depending on which flask gave more DPS, we'll know (for our gear/skill/etc) if Agility > Mastery.

In-game experimentation is limited to the customization available to you -- if you wanted to try a +2000 Agility vs +2000 Mastery, this might not be possible because no flask/potion/gear option(s) exist. Additionally, if you scale back/change gear, your other stats change as well: your hit/exp might change, you might lose a set bonus or a trinket proc. Conveniently, simulation makes this trivial, we can add any amount of extra stat we want, we can maintain hit/exp, and we can always have the necessary bonuses and procs.

Let's generalize our flask example above: imagine we have any flask we want, from -1000 to +1000 Agility and -1000 to +1000 Mastery. No longer is it sufficient to ask: which is better, because the answer is conditional. 10 Mastery might beat 2 Agility, but 666 Agility might beat 900 Mastery.

**One Dimension**
So let's just consider one flask at a time. Try each flask from -1000 to +1000 Agility and record our DPS. The hope is that we get some kind of linear-ish function. Let's fit a line to our data and see if it's reasonable (see plot.) I've indicated that a +1000 gain (going from the -500 to +500 flask) results in a 100K dps increase, since the results are linear, this implies that each stat is worth about 100 DPS.

**Two Dimensions**
Returning to the scenario with two flasks, we can consume one flask of each (like +300 Agility and -200 Mastery) and then record our DPS. Note: we no longer have data that can be plotted in one-dimension, instead we have two dimensions of input (Agility, Mastery) which map to a certain amount of DPS. Similar to how we can fit a line to the one-dimensional example, we can fit a "plane" to the two-dimensional example.

Note: if you look at this plot straight-on from either delta (where you can't see the depth caused by the other delta), it appears exactly like the one-dimensional case.

**Assumption: Local Linearity**
The fact that we can model the one-dimensional case as a line and the two dimensional case as plane (and higher dimensional cases as a hyperplane) is important because it greatly simplifies the implications. For example, if the one-dimensional data wasn't linear, then going from 10000 to 11000 Agility (gain of +1000) might result in 2000 DPS, but going from 9000 to 10000 Agility (also a gain of +1000) is only 1500 DPS. This would mean that in addition to your stat weights, you need an additional piece of information.

It's definitely true that a [450] Cat has completely different stat weights than a [580] Cat, but a [582] Cat (+1000) or a [572] Cat (-1000) is probably very comparable to a [580] Cat. In a topological sense, the stats are "locally" smooth even if they have higher-order scaling. This is similar to how the Earth feels flat to us (humans) even though the Earth is a sphere -- locally, the surface is approximately a flat plane. The same feeling is true regardless of us standing on a large planet (580) or a small moon (450).

**Assumption: Local Independence**
When we were only testing a single stat with flasks ranging from -1000 to +1000 Agility, there were only 2001 possible situations (including 0 Agility). However, when we moved to testing two flasks, there become far more than 4002 situations -- there are actually more 4M (2001^2) permutations! If we were testing 4 different stats, 16 trillion (2001^4) permutations! So to make the problem a bit more tractable, we can assume that stats don't effect each other. This allows us to test Agility by itself and then test Mastery by itself.

Since we have local linearity, local-independence is a reasonable assumption, however it's clear from the damage equations, many stats (Agility and Mastery specifically) have synergistic value. For example, if we know 1 Agility = 2 Mastery, even though 1000 Agility = 2000 Mastery, it would probably be better to have 500 Agility and 1000 Mastery.

**Stat Weight Simulation**
Catus (and Simc) compute stat weights using the "delta" method. For each stat we want to test, we drink a small flask of that test and then record our DPS. Since we already know that even if our stats are fixed, our DPS follows a distribution and can't be represented properly by a single value, we repeat this process a bunch of times. Some stats have breakpoints when you change them. Hit has no value beyond 7.5% and Expertise is less valuable beyond 7.5% and has no value beyond 15%. For these stats, instead of drinking a flask that increases our Hit or Expertise, we can drink a flask that reduces it.

**Basic Instructions**
1. import your kitty

2. setup your

buffs/debuffs/etc
3. find "Simulator: Stat Weights"

4. check the stats you want to simulate

5. recommended: force cap of 7.5% for both Hit/Exp (the Hit/Exp stats don't have to be enabled for their caps to be applied)

6. recommended: [x] Agility, [x] Weapon Damage, [x] Mastery, [x] Haste, [x] Crit

7. click "Generate Weights"

**Iterations** = # of simulations to perform per stat.

**Delta** = amount of stat increase (ie. the size of the "flask" as described above)

**Inert** = some stats require specific values, Rune for example requires 1:1:1 reforge with Mastery as the highest. Using "Inert Deltas" prevents the new stats from influencing the 1:1:1 breakpoint. Inert stats are similar to the Mastery buff (+3000 Mastery) which is invisible to the Rune proc equation.

**Force Cap** = ignore your current Hit/Exp, set Hit/Exp equal to the provided cap.

**Group** = Mastery/Haste/Crit are grouped into one (if delta = 900, +300 of each)

**Report Example**Code: Select all

```
[Weights] (DPS/Stat)
Name DPS Stdev Gain Error Weight Error Delta
Baseline 452.5K 23.02K 0 728 0.00 0.81
Agility 463.8K 23.82K 11.23K 1048 12.48 1.16 +900 Agility
Weapon Damage 458.0K 23.96K 5493 1051 6.10 1.17 +900 Weapon Damage
Critical Strike 456.9K 24.84K 4369 1071 4.85 1.19 +900 Crit
Haste 455.3K 23.49K 2726 1040 3.03 1.16 +900 Haste
Mastery 455.2K 22.95K 2643 1028 2.94 1.14 +900 Mastery
```

Note: there is a section called [Import String] which contains the stat weight information in a format that is accepted by the (Import Weights) button in the "Maximize Stats" reforger in Catus. You can copy/paste this text to quickly import the new weights.

**Iteration and Stability**
Since we've made a bunch of locality assumptions, the biggest problem with stats weights is that they only are valid if they don't cause your gear to change much. If you're currently reforged with (Agility = 6, Mastery = 3, etc...) and the simulator suggests similar weights, and when you reforge with the new weights nothing changes, then you're locally optimized! However, if your results suggest (Mastery = 10, Agility = 3, ...), when you apply this reforge, your stats will shift by thousands of stat points, much much larger than the simulated delta (typically about 1000.) If this happens, you need to recompute your stat weights (using the same process) and try again. It's possible to get stuck in a loop: start with Agility as best, sim say Mastery is best, reforge to Mastery, sim says Agility is the best, ... This means your delta is not sized correctly.

**Stat Weight Simulation: Heroic**
As I hinted at above, there's a better way to calculate the stat weights. The delta simulation (except when Group is enabled) does not record DPS information for combinations of stats. Even though we have a linear and independence assumption, we still might be poorly approximating the gain achieved when more than one stat is increased at a time.

The (Sample Space) button does the following: it randomly picks a flask [-Delta, +Delta] for each of the selected stats, drinks them all, and records the DPS. It then gives you a CSV file with the simulated results and unique stat deltas.

Code: Select all

```
DPS,DeltaDPS,Agi,Mastery,Haste,Crit
433505,-16285,284,-126,400,-560
415503,-34287,-11,182,-377,-166
479250,29460,180,-35,426,-65
481897,32107,-179,480,-741,127
```

**Visualization**
Similar to the two-dimensional example above, you can think of these as 4-dimensional points (Agility,Mastery,Haste,Crit.) It's difficult to plot this properly (4+1 = 5 dimensional data), but you can make multiple two-dimensional plots to help visualize the data: Agility & Mastery, Agility and Haste, Agility and Crit, etc...

**Least Squares** (

source)

Least Squares is an algorithm for finding the "best fit linear hyperplane". You can perform this analysis in Excel, Matlab, Mathematica, etc. Essentially, we're trying to solve the equation DeltaDPS(a,m,h,c), where a = Agility, m = Mastery, h = Haste, c = Crit, such that given some permutation of (a,m,h,c), it can produce an estimate of the expected DPS.

Code: Select all

`DeltaDPS(a,m,h,c) = Wa * a + Wm * m + Wh * h + Wc * c`

The equation is linear with regard to 4 weights: Wa, Wm, Wh, and Wc. Since the data won't fit perfectly (and simulation results have randomness), we try to minimize the difference across all examples between the predicted DPS and the observed DPS.

**Comparison: Least Squared Fit vs Observed DPS**
Pretty good fit across 40K DPS range using [-900,+900] deltas.

Earlier discussion:

http://fluiddruid.net/forum/viewtopic.p ... 725#p20119