[Question]
  [
This is a copy cat question of [Simplify ijk string](https://codegolf.stackexchange.com/questions/226278/simplify-ijk-string) applied to the other nonabelian group of order 8. See also [Dihedral group composition with custom labels](https://codegolf.stackexchange.com/questions/185140/dihedral-group-d4-composition-with-custom-labels).
## Challenge
Given a string made of `r` and `s` interpret it as the product of elements of the dihedral group \$D\_8\$ and simplify it into one of the eight possible values `""`, `"r"`, `"rr"`, `"rrr"`, `"s"`, `"rs"`, `"rrs"`, and `"rrrs"`. The empty string denotes the identity element \$1\$.
The evaluation rules are as follows:
$$
rrrr = 1\\
ss = 1\\
sr = rrrs
$$
The multiplication on the dihedral group is associative but not commutative. This means that you may do the simplification in any order, but you cannot reorder the items.
For the I/O format, function parameter and return from a function should be done as a string or list. You may output any amount of leading and trailing whitespace (spaces, tabs, newlines). You may use any other pair of distinct characters for `r` and `s` except for a tab, space, or newline. (If you really want to you can pick `r` or `s` to be whitespace, you can as long as you don't have leading or trailing whitespace.) It's also fine to use numbers for `r` and `s`, for example if you take `0` for `r` and `1` for `s`, it would be okay to do I/O like `[1, 0] ==> [0, 0, 0, 1]`.
## Test cases
```
"" -> ""
"r" -> "r"
"rrr" -> "rrr"
"s" -> "s"
"rs" -> "rs"
"rrs" -> "rrs"
"rrrr" -> ""
"rrrrrr" -> "rr"
"sr" -> "rrrs"
"rsr" -> "s"
"srsr" -> ""
"srr" -> "rrs"
"srs" -> "rrr"
"rsrsr" -> "r"
"rrsss" -> "rrs"
"sssrrr" -> "rs"
```
## Reference implementation
Here is a Javascript reference implementation.
```
function f(x) {
  let lastx;
  while(lastx !== x){
    lastx = x;
    x = x.replace("rrrr", "");
    x = x.replace("sr", "rrrs");
    x = x.replace("ss", "");
  }
  return x;
}
```
  
[Answer]
# [J](http://jsoftware.com/), 23 bytes
```
~:/I.@,~4|[:-/1#;._1@,]
```
[Try it online!](https://tio.run/##jY8/C8IwEMX3fopDwbOQphacUioBQRCcXKU4iG11ULgDF6VfPabN@afg4BBe3uPld7mzG2nACgqDCmZg/Ek0LLeblWtNutZWtfPHziRpNs71PrOqdHFU@zogY1FG9ely6x0x3tsyOh6aK3ShrWw90QtAzGGqkDDOfYkoWA6WMTz4qzSgko9Dl14abhy8F0FLM7Sky@8BP9BMLCQRFqKgiblPvHQzPxt8fWq4jwDQPQE "J – Try It Online")
Takes a boolean vector where `0` represents `r` and `1` represents `s`, and returns the result in the same encoding.
### How it works
Imagine evaluating the chunks of \$r^n s r^m s\$ from the start. If we evaluate \$sr\$ in the middle \$m\$ times, we get \$r^{n+3m}s^2 = r^{n+3m}\$. We can repeat the process to the end. Let's represent the input as a sequence of integers which represent the number of \$r\$'s when separated by \$s\$'s, like `sssrrr -> [0, 0, 0, 3]`. Then the following holds:
* The alternating sum (`[a, b, c, d, ...] -> a - b + c - d + ...`) modulo 4 is the final number of \$r\$'s.
* The length plus 1 modulo 2 is the final number of \$s\$'s.
```
~:/I.@,~4|[:-/1#;._1@,]  NB. Input: a boolean vector
              1#;._1@,]  NB. Get the lengths of runs of r's between s's
        4|[:-/  NB. Alternating sum modulo 4 = the number of final r's
~:/             NB. Reduction by unequal on the original input,
                NB. i.e. the number of s's in the input mod 2
                NB. = the number of final s's
   I.@,~        NB. Reverse concat and generate that many 0's and 1's
```
# [Jelly](https://github.com/DennisMitchell/jelly), 15 bytes
```
ṣ1ẈṚḅ3%4,SḂ$Ø.x
```
[Try it online!](https://tio.run/##y0rNyan8///hzsWGD3d1PNw56@GOVmNVE53ghzuaVA7P0Kv4/6hxX1Fx5qON64Do0M5HDTMPtz9qWvNwdzdQorgo8v//aHV1HQX1IjBRBKaKwWwICaOKYApgaiD8YigHRsO4UEmoqqLiYrAIkAJpjwUA "Jelly – Try It Online")
Same algorithm as above. Doesn't feel well golfed to me though; maybe I missed some good alternative built-ins.
```
ṣ1ẈṚḅ3%4,SḂ$Ø.x  Input: a list of zeros and ones
s1Ẉ              Split at ones, then get length of each chunk
   Ṛḅ3%4         Reverse, evaluate in base 3, modulo 4
        ,        Pair with...
         SḂ$     Sum % 2
            Ø.x  Generate that many zeros and ones respectively
```
[Answer]
# perl -p, 31 bytes
```
1while s/rrrr|ss//||s/sr/rrrs/;
```
Takes advantage of substitution returning truthy iff anything was substituted.
[Answer]
# [Retina 0.8.2](https://github.com/m-ender/retina/wiki/The-Language/a950ad7d925ec9316e3e2fb2cf5d49fd15d23e3d), 18 bytes
```
{`rrrr|ss
sr
rrrs
```
[Try it online!](https://tio.run/##HYyxEgAgCEJ3vrKGhpYGaKt/N8ITfcehHHuuXnUaXVcCRBhVhQAEuiPGiWnSXxmBb@RW/mI59gA "Retina 0.8.2 – Try It Online") Straightforward port of the reference implementation.
[Answer]
# [Python 2](https://docs.python.org/2/), 58 bytes
* *[@dingledooper](https://codegolf.stackexchange.com/users/88546/dingledooper) saves 12 bytes by switch to Python 2 and finding out some bit-wise operators expression which I cannot understand!*
```
p=q=0
for b in input():p^=b;q+=~p/~b^p
print q%4*[0]+p*[1]
```
[Try it online!](https://tio.run/##XY3NCoMwEITv@xSLUPCnUFN6Sslb9CYK1aYoFLPGSPXiq6cRqymFXdhvdoahydSqPdtKPSQKDILAkuhECk@lscSmdUODCSNOhSivXSJmOs1lQUC6aQ12h0ucpXlCccZy6@IARk8cEN9185J404PkKEdZhUtFBHKsJBmOdO97m@Xgwm6PuIy72EpsF/31dXjwof3DvPAHP7K37p50A7b@2QZbyQc "Python 2 – Try It Online")
I/O as an array of integers, r = 0, s = 1.
JavaScript needs [too many bytes](https://tio.run/##dY7BTsMwDIbveQpfNidLl1HgtCmdeA5AWhSyqag0qV2hIcazlyQHbki28@t3/Nnv7tOxpz7N2zG@heVsF7bdszGGX82HS9LbbuuPSev9pO3DZpOaZCd7p9brJyL3JafVo26Vlml1f7shqmUOPHvHgcHCSZAgIsGCctSk6lQzKy5PLVUUo9jEzCJn/nYynIZ@lvgyojqIP3o97gq2g28B0OdlV0MhDc4HuTO7SwO@NHOxgIxwBGwR9oBNwQDEPHGWfdU@jhyHYIZ4kfF/SlspXCmEKo/@qMPyCw) to repeat some strings.
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E), ~~16~~ ~~14~~ ~~13~~ ~~12~~ 10 bytes
*-3 thanks to [ovs](https://codegolf.stackexchange.com/users/64121/ovs).*
*-2 thanks to [Kevin Cruijssen](https://codegolf.stackexchange.com/users/52210/kevin-cruijssen).*
```
Δ48bγKT₄R:
```
[Try it online!](https://tio.run/##yy9OTMpM/V9TVvn/3BQTi6Rzm71DHjW1BFn9r9X5b8BlYGDAZchlAERgbAAWAQsCWYYgCkyAGSABkLCBoaEhFxCDlRkaAAA "05AB1E – Try It Online") Beats all other answers. Uses `0` for `r` and `1` for `s`.
```
Δ48bγKT₄R:  # full program
Δ           # while top of stack changes:
         :  # replace all instances of...
      T     # 10...
         :  # in...
            # implicit input...
            # (implicit) or top of stack if not first iteration...
     K      # with none of the elements of...
 48         # literal...
   b        # in binary...
    γ       # split into chunks of consecutive equal elements...
         :  # with...
       ₄    # 1000...
        R   # in reverse
            # implicit output
```
[Answer]
# JavaScript (ES6), ~~54~~ 53 bytes
Expects a string with `1` for `s` and `2` for `r`. Returns another string in the same format.
```
f=s=>s-(S=s.replace(/2222|1./,s=>s%3?"":2221))?f(S):s
```
[Try it online!](https://tio.run/##dU89a8MwEN39Kw5BQSK2TJohkKBkytwhYwhByJKbYixzF0qh7W93T8GxukSD7t37gvuwn5YcXodb1cfGj2MwZHZUyaMhjX7orPOyfuX3s9R1mbSX1V6IDTNLpfZBHtWGxu2pABCiTD9OAydA0/6YGWC2ZveDo5nIKFOzafYj0cQySHXFudAh4sG6d0lgdvDNIt0QDPw7TddtCS7J4sJd@to3/ustSKfUlv3oOQpBcu6@u9hT7LzuYitJD7Y59I1cK1iAqLiCJyeetp/cOdX@qvEP "JavaScript (Node.js) – Try It Online")
### Commented
```
f = s =>           // f is a recursive function taking the input string s
  s - (            // test whether s is different from the updated string S
    S = s.replace( //   which is obtained by looking for the 1st occurrence
      /2222|1./,   //     of either "2222", "11" or "12"
      s =>         //     and replacing it with
      s % 3 ? ""   //     an empty string for "2222" and "11"
            : 2221 //     or "2221" for "12"
    )              //   end of replace()
  ) ?              // if s is not equal to S:
    f(S)           //   repeat the process with S
  :                // else:
    s              //   we're done: return s
```
[Answer]
# [J](http://jsoftware.com/), 29 27 bytes
```
rplc&(sr`rrrs,,.rrrr`ss)^:_
```
[Try it online!](https://tio.run/##bY/BCgIxDETvfkXwYF3oFs@FPQmePPkBurC4iAjKzP9TW6hNwB5CkscwkzzTNrhVpihOvBwk5hqDHC/nU8Lntez2xAyA3ofcMJPDNd7SsLkvj7c4J2OUNfe6w8lUdjQA/DRlrJRVxiZjUykzUKlxMyGWWq4W/AuHIhURnXii9w/NqWrZNcgjO79mWPzSFw "J – Try It Online")
* `rplc&(sr`rrrs,,.rrrr`ss)` Keep doing the needed replacements...
* `^:_` Until it stops changing
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), 24 bytes
```
œṣØ0Fœṣ1x4¤FœṣØ.j14BFµÐL
```
[Try it online!](https://tio.run/##y0rNyan8///o5Ic7Fx@eYeAGZhhWmBxa4gYV08syNHFyO7T18AQfiLJHDXMUdO0UHjXMfbhj0cMdXQ93TvN/uKPJ@XD7w93djxr3FRVzPdy95XD7o6Y1kf//KymBFCspcSkVQVhFIGYRjFME4hZDOMUgGSi7CMyB86BcmDYoB2EKyBCEkRCDihCmFsN5YE4RsqnFCEuKIPqgaiEOLS5GcQOQi7C2WAkA "Jelly – Try It Online")
Uses `1` for `r` and `0` for `s`
## How it works
Jelly does not have a good time with replacements. Its translate atom, `y`, only handles replacing specific, individual values (such as integers) with others, and cannot work with replacing groups of items.
Instead, we split on the values we want to replace, and join with their replacements
```
œṣØ0Fœṣ1x4¤FœṣØ.j14BFµÐL - Main link. Takes a list of bits B on the left
                     µÐL - Apply the chain to the left on B until it reaches a fixed point
  Ø0                     -   Yield [0, 0]
œṣ                       -   Split around 0,0
    F                    -   Flatten
       1x4¤              -   Yield [1,1,1,1]
     œṣ                  -   Split around 1,1,1,1
           F             -   Flatten
              Ø.         -   Yield [0, 1]
            œṣ           -   Split around 0,1
                j14      -   Join with 14
                   B     -   Convert to binary
                    F    -   Flatten
```
[Answer]
# [Factor](https://factorcode.org/), ~~69~~ 65 bytes
```
[ [ "sr""rrrs""rrrr""" "ss"""[ replace ] 2tri@ ] to-fixed-point ]
```
[Try it online!](https://tio.run/##bZGxjgIhEIb7fYq57dfiSk0u111sbMxVGwvEWUNcAWfmEo3x2fdQQFmVhvDly88/0Cktjobf5XzxM4UdksUe2PdGxNgtaLdfG6uCwsB4@EOrkcETipw8GSswq@aLKWxd31XVuYKw6hri@oDmK5wipLqElClFnihlziObs51wsu848Rzy4DF93IMiznK@kEbRRQiXDfmu82s0Pw1TyG@HpJRy448XYeb6TQhz2Tvgy9BCe2se@8Z5w@sHN2wtEPpeaYQVfAqZ77CLazpzxE3j3fXvVsNeeWBRejcZ/gE "Factor – Try It Online")
*-4 thanks to @Bubbler*
* Abuse the fact that strings don't require trailing whitespace in the version of Factor TIO uses.
* `2tri@` Call a quotation on three pairs of objects. e.g. `1 2 3 4 5 6 [ + ] 2tri@` -> `3 7 11`.
* `to-fixed-point` Call a quotation until its input stops changing.
[Answer]
# [Charcoal](https://github.com/somebody1234/Charcoal), ~~25~~ ~~21~~ 20 bytes
```
⁻⭆⪪θs×ι⊕⊗κ×r⁴×s﹪№θs²
```
[Try it online!](https://tio.run/##S85ILErOT8z5/z@gKDOvRMM3M6@0WCO4BMhJ900s0AguyMks0SjUUVAqVtLUUQjJzE0t1sjUUfDMSy5KzU3NK0lN0XDJL03KAdLZmkAAU6NUpKSjYAIUsOaCmAwVLgYK@@anlObkazjnl@YhmW0EUvz/f3HRf92yHAA "Charcoal – Try It Online") Link is to verbose version of code. Based on a method @Bubbler mentioned in chat. Explanation:
```
⁻⭆⪪θs×ι⊕⊗κ×r⁴
```
Split the input on `s`s, repeat alternate segments thrice, then use string substitution to reduce the length modulo `4`.
```
×s﹪№θs²
```
Output an `s` if there were an odd number of `s`s in the input. `⁻⁻θr¦ss` also works for the same byte count, but I can't find anything shorter.
~~20~~ 19 bytes by taking I/O as strings of `0`s and `1`s:
```
⁻⭆⪪θ1×ι⊕⊗κ×0⁴×1﹪Σθ²
```
[Try it online!](https://tio.run/##NYyxDgIhEER7v4JQ7SWYHMbO1saC5BL8AeSIEhe448DfX9eo00zmZWb8w1VfHBJNNeYGJua@gW0c7sYtYBeMDVYlpJaDEteYwgZRiUv2NaSQW5jhXPoN2Z8D69@Ro1TiyOC0@z7/sGZsytyxgO0JVh4cPi0iPdL@hW8 "Charcoal – Try It Online") Link is to verbose version of code. Explanation: As above but counts `1`s by taking the digital sum of the input.
Previous 25-byte string substitution answer:
```
Ｗ№θsr≔⪫⪪θsr¦rsssθ⁻⁻θ×r⁴ss
```
[Try it online!](https://tio.run/##S85ILErOT8z5/788IzMnVUHDOb80r0SjUEdBqbhISVNTwbG4ODM9T8MrPzNPI7ggJxMhB6SKiouLQYxCTWuugKJMoEbfzLzSYigJVBiSmZtarKFUpKSjYKIJ0gFSr2n9/39x0X/dshwA "Charcoal – Try It Online") Link is to verbose version of code. Explanation:
```
Ｗ№θsr
```
While the input contains `sr`...
```
≔⪫⪪θsr¦rsssθ
```
... replace all occurrences of `sr` with `rsss`.
```
⁻⁻θ×r⁴ss
```
Remove `rrrr` and `ss` and output the result.
I tried a numeric approach but it turned out to be slightly longer at 29 bytes:
```
≔⁰θＦＳ¿Σι≦⁻³θ≦⁺²θ§⪪”)∨'✂/Ｏ;”2θ
```
[Try it online!](https://tio.run/##XYyxCsMgGIT3PsWP0y9Y@HXpkCljoIFAniCkmgrWpFFL395qsnW5O7j7bn5O@7xOLuc2BLt4JAFv3lzMugN2fktxjLv1C3IO1gCO6YW25H7aTuCuTcTe@hQE3A4WtAv6bzC42qvzeyiHEdvY@Yf@4rg5G5EpIpKK1KHFqpKSTABTjFeQNzlLyteP@wE "Charcoal – Try It Online") Link is to verbose version of code. I/O is as strings of `0`s and `1`s. Explanation: The values are encoded to integers equivalent to `0..7` (modulo `8`) in the order , `01`, `0`, `1`, `00`, `0001`, `000`, `001`. A `1` subtracts the integer from `3` while a `0` adds `2` to the integer.
```
≔⁰θ
```
Start with `0`.
```
ＦＳ
```
Loop over the input.
```
¿Σι
```
If the digit is nonzero, ...
```
≦⁻³θ
```
... then subtract the integer from `3`, ...
```
≦⁺²θ
```
... otherwise add `2` to it.
```
§⪪”)∨'✂/Ｏ;”2θ
```
Index into a look-up table to find the final result. (The number of zeros is actually given by `(x>>1)^(x&1)` and the number of ones by `x&1` but Charcoal has no bitwise XOR operator, so the best I could do was this look-up table.)
I was able to save a byte by using two variables:
```
≔⁰θ≔⁰ηＦＳ¿Σι≦¬θ≦⁺⊕⊗θη×0﹪η⁴×1θ
```
[Try it online!](https://tio.run/##XU3JCoMwEL33KwZPM5CCQm@eCr0ItQj2B6yOGoiJZunvp@kCQk9v4S393NnedCrGs3Ny0pgL2Kg87GpOajQWsNJr8K23Uk9IBHIEbMOCMvG6W3@Fm/GfAWDlePevPHpsVHACKt1bXlh7HvBiwkMl3Ii@R01a93iXCzvM8kxAbYagDM4CTkT/gSJ7f1EZY5HH41O9AA "Charcoal – Try It Online") Link is to verbose version of code. I/O is as strings of `0`s and `1`s. Explanation: The two variables track the number of `1`s and `0`s. If there are an odd number of `1`s so far then each input `0` adds `3` otherwise it adds `1`.
```
≔⁰θ≔⁰η
```
Start with `0` `1`s and `0` `0`s.
```
ＦＳ
```
Loop over the input.
```
¿Σι
```
If the digit is nonzero, ...
```
≦¬θ
```
... then invert the parity of the `1`s, ...
```
≦⁺⊕⊗θη
```
... otherwise add `1` or `3` `0`s as appropriate.
```
×0﹪η⁴
```
Output the number of `0`s (mod 4).
```
×1θ
```
Output a `1` if appropriate.
[Answer]
# [Vyxal](https://github.com/Lyxal/Vyxal), ~~17~~ 16 bytes
```
λ88ok2‹o89k2⇩V;Ẋ
```
[Try it Online!](http://lyxal.pythonanywhere.com?flags=&code=%CE%BB88ok2%E2%80%B9o89k2%E2%87%A9V%3B%E1%BA%8A&inputs=%60888999%60&header=&footer=)
Creative input abuse. Takes r as 9 and s as 8.
```
λ             ;Ẋ # Repeat until input doesn't change
 88o             # Get rid of 88s (`ss`)
    k2‹          # 10000 - 1 = 9999 (=`rrrr`)
       o         # Get rid of those as well
        89       # 89 (`sr`)
          k2⇩    # 10000 - 2 = 9998 (`rrrs`)
             V   # Replace (`sr` with `rrrs`)
```
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E), 15 bytes
Uses `0` and `1` for `r` and `s`.
```
Δ•BƵ?ù•₂вb€¦ι`:
```
[Try it online!](https://tio.run/##yy9OTMpM/V9Waa@koGunoGRfqVRUrKRkYKj0qGHh/3NTHjUscjq21f7wTiDjUVPThU1Jj5rWHFp2bmeC1f9akDKQcqBSnf/RSko6CkpFYKIITBWD2RASRhXBFMDUQPjFUA6MhnGhklBVRcXFYBEgBdIeCwA "05AB1E – Try It Online")
```
Δ           # Until the output doesn't change:
•BƵ?ù•₂в    # Compressed integer list
              [16, 1, 7, 1, 6, 17]
b€¦         # Convert to binary and remove most significant digit
              ["0000", "", "11", "", "10", "0001"]
ι`          # Split into two separate lists by alternating the values
              ["0000", "11", "10"], ["", "", "0001"]
:           # Replace
```
[Answer]
# Java, 76 bytes
```
s->{for(;s!=(s=s.replaceAll("rrrr|ss","").replace("sr","rrrs")););return s;}
```
[Try it online!](https://tio.run/##lZOxbsMgEIZn@ykoS6BJeAHqSF26dcpYdaCOHeFiQHc4UuT62d2rkkode7ec7v5PP/xIDO7i9sPpc/VjTlDEQLOZig@mn2JbfIrm0dZ5@gi@FW1wiOLV@SjmWlDd91hcoXZJ/iRGUtWxgI/nt3cHZ9RzXb3cvZ5uwu7WDn2z4v4w9wmUxYdGYYMGuhxc2z2HoCRQfSHKnZT6V1ASgRakoNTaagtdmSAKtMta2bo6XrF0o0lTMZkOKSGqjdxse@NyDldFTlua9T9IYKDAgJHhy2F5MPDi8RJyvJFlzKN51qxLszICIsOd4L/P/fPRlnpZvwE)
[Answer]
# [Red](http://www.red-lang.org), 82 bytes
```
func[s][while[parse s[some thru[remove["rrrr"|"ss"]| change"sr""rrrs"]to end]][]s]
```
[Try it online!](https://tio.run/##TZAxDsMwCEXn5hSIvXvVoYfoihiimNSREjuCpF16d9dVJAcWnp/9kYxKKE8JxN14hzLuaSBj@sRpFlp7NQEjy4vAFnUnlSW/hVBr4RfNkL8wxD69BE3x76vaMkgKzMTGZcwq/RDBgDqohQhH1wba0Jo7yaP6kM@d3pz07LV77JJq1m4qHuOZVp3SVncRYMlzqP@4AV4feJxGMOZL@QE "Red – Try It Online")
[Answer]
# [Bash with sed](https://www.gnu.org/software/bash/), ~~86~~ 84 bytes
Saved 2 bytes thanks to [Digital Trauma](https://codegolf.stackexchange.com/users/11259/digital-trauma)!!!
```
until [[ $a = $1 ]];do a=$1
set -- `sed 's/sr/rrrs/;s/rrrr\|ss//'<<<$a`
done
echo $a
```
[Try it online!](https://tio.run/##fVHLasMwELz7KxYhyAMUkZYeQuxeQr8iTokbS1gQ5LKrQCDtt7urtU3ppQJ5xp7ZESN/NNQN/hYvKfQR/HL1GG4xhSscj6AbqEBv4XTatz00ld4W5BIYA2dyLSzIElpEJLunjFh/EVm7KMtSN@ei7aMr3KXrOWj4LnyPQBAiKKtA8WB@ogQw46z8zjmCmUyMLROKOXvHU8WPMkeZCOI0R5KAo4fm04jmXGaSR4q7FcArVXo51jJ2s9bGSA9aieh@xffN2v4ViUUPOk3W3NhwzVrpVCswr8CMmCnRg893y18UVBWjU/mCIXUuip7XJ4aYPEfc357q@@7A@7mO47y7kvvP@DIbfZBfMPwA "Bash – Try It Online")
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), ~~21~~ 18 [bytes](https://github.com/DennisMitchell/jelly/wiki/Code-page)
Not Jelly's forté! ~~Perhaps~~ There is [a clever way](https://codegolf.stackexchange.com/a/226380/53748) to do it though~~?~~.
```
2“Ð¡©¡¦Ñ‘ḃœṣjƭƒµÐL
```
A monadic Link that accepts a list of `1`s (`r`) and `2`s (`s`), and yields the same.
**[Try it online!](https://tio.run/##y0rNyan8/9/oUcOcwxMOLTy0EoiXHZ74qGHGwx3NRyc/3Lk469jaY5MObT08wef/o8Z9RcWZjzauO9z@cHc3mPf/f3FxcVFREQA "Jelly – Try It Online")** (The footer translates from an `rs` string, calls the link and translates back.)  
Or see the [test-suite](https://tio.run/##y0rNyan8/9/oUcOcwxMOLTy0EoiXHZ74qGHGwx3NRyc/3Lk469jaY5MObT08wef/o8Z9RcWZjzauO9z@cHc3mMd1dM/h9kdNa9z//49WUtJRKgLhIhBZDGKBCShZBJWDSoN5xRAmlIJyIBIQBUXFxSA@kARpiwUA "Jelly – Try It Online").
### How?
```
2“Ð¡©¡¦Ñ‘ḃœṣjƭƒµÐL - Link: list of integers (in [1,2]): S
               µÐL - loop until no change f(X=S)->X:
2                  -   two
 “Ð¡©¡¦Ñ‘          -   code-page indices = [15,0,6,0,5,16]
         ḃ         -   to bijective base (2) -> [[1,1,1,1],[],[2,2],[],[2,1],[1,1,1,2]]
              ƒ    -   start with X and reduce using:
             ƭ     -     tie (call each of these two links in turn):
          œṣ       -       split (left) at sublists equal to (right)
            j      -       join (left) with (right)
                       }...i.e:
                              split at [1,1,1,1], join with []
                              split at [2,2], join with []
                              split at [2,1], join with [1,1,1,2]
```
[Answer]
# [R](https://www.r-project.org/), ~~68~~ 66 bytes
```
function(x){while(x!=(x=sub("rrrr|ss","",sub("sr","rrrs",x))))0;x}
```
[Try it online!](https://tio.run/##K/qfZvs/rTQvuSQzP0@jQrO6PCMzJ1WjQtFWo8K2uDRJQ6kICGqKi5V0lJR0wALFRUA2UBAoVKEJBAbWFbX/0zSUlDS50iDKESwYu7i4GMz@DwA "R – Try It Online")
*-2 bytes thanks to [iota](https://codegolf.stackexchange.com/users/99986/iota)*
Applies reference implementation.
[Answer]
# Python 3.8, 86 bytes
```
f=lambda s,r=str.replace:f(s)if s!=(s:=r(r(r(s,"rrrr",""),"ss",""),"sr","rrrs"))else s
```
[Try it online!](https://tio.run/##ZY5BC0IhEITv/Qrbk4J06RIP/DFWSg/sJTNe@vXmIwrU3ct@M8Ow@V0er@18yag1uuSf17tXtHAsOCHk5G9hiZpmjYpHp7k46H1pBW3Eihgr5O/YlaZTjAmJQbFmrFvRUTffHP6AntAze3fAiTG1TYVDgqM9CVNgLBgrQfaZxt836gc)
[Answer]
# [Python 3](https://docs.python.org/3/), 90 bytes
```
f=lambda x,s=str.replace:f(s(s(s(x,"r"*4,""),"ss",""),"sr","rrrs"))if x not in"rrrs"else x
```
[Try it online!](https://tio.run/##VY/BbsIwDIbPy1NYPiVTxmU7IXXXvcBeIAUXIoUS2QGKJp6dpU1KQTnk/@z4/514Tftj/3ln2nlJxNAAolLxGtn3KdN0K7Wlrkg9mLV624Vj6wLMU@rtaX64d01wh3brYLDSSOIVUwxuQ@tOy3QGi4zvXxbRWBTBKjgLZhY0xncwQH9M4PtSoiCUrS97Hwh@@UR5C2ehzYEHFzWdXbD5cTwlbVYSg08a4eMbstfLdp12uVD/pzv88Wfq4S9vyLlzs0BDpE2iba21Y03cZV15tjI30AeXNnuSqTUHNNDeDJo7lnRU@aeT4lHyDDyiFJCxUzVP8KCK81iFxWU0WSyLES@u8qAJ@NlVlhAuc/VtWVTkZYeMS6zgPw "Python 3 – Try It Online")
[Answer]
# [Stax](https://github.com/tomtheisen/stax), 19 [bytes](https://github.com/tomtheisen/stax/blob/master/docs/packed.md#packed-stax)
```
╚ò/i»┬⌐ÇÑ ╒‼î┐╟▌z¥²
```
[Run and debug it](https://staxlang.xyz/#p=c8952f69afc2a980a520d5138cbfc7dd7a9dfd&i=%22%22%0A%22r%22%0A%22rrr%22%0A%22s%22%0A%22rs%22%0A%22rrs%22%0A%22rrrr%22%0A%22rrrrrr%22%0A%22sr%22%0A%22rsr%22%0A%22srsr%22%0A%22srr%22%0A%22srs%22%0A%22rsrsr%22%0A%22rrsss%22%0A%22sssrrr%22%0A&m=2)
Plain Regex.
Bubbler's method is a bit long in Stax since zeroes get converted to spaces.
[Answer]
# [sed 4.2.2](https://www.gnu.org/software/sed/), 26
```
:
s/rrrr|ss//
s/sr/rrrs/
t
```
[Try it online!](https://tio.run/##HYoxDsAwCAN3/yVi73vSoUtT2Rn79lIDwnCc0DkzDyjoeqUIs1inAjsThBkC3R22aWlSrR4NJUpTEpx6@9azr3UrB38 "sed 4.2.2 – Try It Online")
[Answer]
# [///](https://esolangs.org/wiki////), 21 bytes
```
/sr/rrrs//rrrr///ss//
```
[Try it online!](https://tio.run/##K85JLM5ILf7/X7@4SL@oqKhYH0QW6evrFwOZ/4uLi4G8/wA "/// – Try It Online")
Input is appended to the end of the code.
A straightforward implementation of the three evaluation rules. Note that after every `sr` is replaced by `rrrs` recursively, the resulting string is of the form \$r^xs^y\$, and neither of the remaining rules will change this fact. Thus, we do not need to revisit `sr -> rrrs` after applying the other two rules.
[Answer]
# Pure [Bash](https://www.gnu.org/software/bash/), 75 bytes
```
a=${1//sr/rrrs};a=${a//rrrr/};a=${a//ss/};[ "$a" = "$1" ]&&echo $1||. $0 $a
```
[Try it online!](https://tio.run/##S0oszvj/P9FWpdpQX7@4SL@oqKi41hrET9QHcYr04bziYiA7WkFJJVFJwRZIGSopxKqppSZn5CuoGNbU6CmoGCioJP7//7@4uBioEQA "Bash – Try It Online") Why use sed when you don't need to?
[Answer]
# [Core Maude](http://maude.cs.illinois.edu/w/index.php/The_Maude_System), 81 bytes
```
mod D is inc LIST{Nat}. eq 0 0 0 0 = nil . eq 1 1 = nil . eq 1 0 = 0 0 0 1 . endm
```
### Example Session
```
             \||||||||||||||||||/
           --- Welcome to Maude ---
             /||||||||||||||||||\
         Maude 3.1 built: Oct 12 2020 20:12:31
         Copyright 1997-2020 SRI International
           Fri May 28 22:50:23 2021
Maude> mod D is inc LIST{Nat}. eq 0 0 0 0 = nil . eq 1 1 = nil . eq 1 0 = 0 0 0 1 . endm
Maude> red nil .
reduce in D : nil .
rewrites: 0 in 0ms cpu (0ms real) (~ rewrites/second)
result List{Nat}: nil
Maude> red 0 .
reduce in D : 0 .
rewrites: 0 in 0ms cpu (0ms real) (~ rewrites/second)
result Zero: 0
Maude> red 0 0 0 .
reduce in D : 0 0 0 .
rewrites: 0 in 0ms cpu (0ms real) (~ rewrites/second)
result NeList{Nat}: 0 0 0
Maude> red 1 .
reduce in D : 1 .
rewrites: 0 in 0ms cpu (0ms real) (~ rewrites/second)
result NzNat: 1
Maude> red 0 1 .
reduce in D : 0 1 .
rewrites: 0 in 0ms cpu (0ms real) (~ rewrites/second)
result NeList{Nat}: 0 1
Maude> red 0 0 1 .
reduce in D : 0 0 1 .
rewrites: 0 in 0ms cpu (0ms real) (~ rewrites/second)
result NeList{Nat}: 0 0 1
Maude> red 0 0 0 0 .
reduce in D : 0 0 0 0 .
rewrites: 1 in 0ms cpu (0ms real) (~ rewrites/second)
result List{Nat}: nil
Maude> red 0 0 0 0 0 0 .
reduce in D : 0 0 0 0 0 0 .
rewrites: 1 in 0ms cpu (0ms real) (~ rewrites/second)
result NeList{Nat}: 0 0
Maude> red 1 0 .
reduce in D : 1 0 .
rewrites: 1 in 0ms cpu (0ms real) (~ rewrites/second)
result NeList{Nat}: 0 0 0 1
Maude> red 0 1 0 .
reduce in D : 0 1 0 .
rewrites: 2 in 0ms cpu (0ms real) (~ rewrites/second)
result NzNat: 1
Maude> red 1 0 1 0 .
reduce in D : 1 0 1 0 .
rewrites: 3 in 0ms cpu (0ms real) (~ rewrites/second)
result List{Nat}: nil
Maude> red 1 0 0 .
reduce in D : 1 0 0 .
rewrites: 3 in 0ms cpu (0ms real) (~ rewrites/second)
result NeList{Nat}: 0 0 1
Maude> red 1 0 1 .
reduce in D : 1 0 1 .
rewrites: 2 in 0ms cpu (0ms real) (~ rewrites/second)
result NeList{Nat}: 0 0 0
Maude> red 0 1 0 1 0 .
reduce in D : 0 1 0 1 0 .
rewrites: 3 in 0ms cpu (0ms real) (~ rewrites/second)
result Zero: 0
Maude> red 0 0 1 1 1 .
reduce in D : 0 0 1 1 1 .
rewrites: 1 in 0ms cpu (0ms real) (~ rewrites/second)
result NeList{Nat}: 0 0 1
Maude> red 1 1 1 0 0 0 .
reduce in D : 1 1 1 0 0 0 .
rewrites: 12 in 0ms cpu (0ms real) (~ rewrites/second)
result NeList{Nat}: 0 1
```
### Ungolfed
```
mod D is
    inc LIST{Nat} .
    eq 0 0 0 0 = nil .
    eq 1 1 = nil .
    eq 1 0 = 0 0 0 1 .
endm
```
I chose to encode `r` as `0` and `s` as `1`. (It would cost 19 more bytes to use `r` and `s` directly instead.)
I am shocked and thrilled that Core Maude is actually competitive in this question! Maude's built-in list module implements lists using the `__` operator (juxtaposition), which is associative and has `nil` as its identity. This means an equation can match any sublist. Since this is just "reduce until done", we don't even need our own function symbol to separate input from output.
We could probably get away with shaving off one byte, but it would not technically be a correct Core Maude program anymore. The existing Maude interpreter does not differentiate between protecting (`pr`) and including (`inc`) modules, but according to the spec our equations would not be valid with protecting.
[Answer]
# [C (gcc)](https://gcc.gnu.org/), ~~118~~ \$\cdots\$ ~~96~~ 95 bytes
```
i;b;p;q;f(char*s){for(;s[i];q+=~p/~b^p)p^=b=s[i++]-48;for(i=p+q%4;i--;*s++=48^i<p);i=p=q=*s=0;}
```
[Try it online!](https://tio.run/##pVLBbtswDL3nKzgDheUoRpM1A7qp6g7DviJxgESVW2Wpq4guli1IP30eJcuGU/RQoAYsUuTj06Mold8r1TRGbIQVe1Ey9bB2Y8yO5ZNjAhemEHsuX@zly2ZlM7uSG0lBzot8fi08xkjL9xdzYfJcjJFzOb9emRubCUrIvRyjnIpTY6oaHtemYtnoOAL6wjFQa6xxUYCEow8myQQSFxYXDAa/XTvjOkCH8atHxV1nu21LEcPEgiFCxtefxECNPlitan0XBb1DjT/Z6w756PlMgMaG2ii2IqP483AgPVOiHrT6pR0JAS8lWR5@fl4evv6g/4snGOyvukoaBjB/z6a60wcqm4ro3gCav/qpZF2D2WUMjPuIAM4DOoN2QIMhEVc7qAAoRJ/3p@0oi7Xb6YrVmTgrhc1zWS52wGE2KCKwsn@Yz01gWNI3sG3Fh@ptIWDLedbtKMWiK2WK6XdIZyl8g3SaDqkC5mPcM8@Ngdulrzqjt0Lg/r28dS92jUiYT77dR8v0BF5Jso5gJUuWyQUuE8hvIXq0VDTkuq2Y9I/BMxaR4DQ6Nf9UuVvfY5P//g8 "C (gcc) – Try It Online")
Uses `'0'` for `'r'`, `'1'` for `'s'`, and [dingledooper](https://codegolf.stackexchange.com/users/88546/dingledooper)'s formula for [tsh](https://codegolf.stackexchange.com/users/44718/tsh)'s [Python answer](https://codegolf.stackexchange.com/a/226384/9481).
]