[Question]
  [
Two words are *[isomorphs](http://www.questrel.com/records.html#spelling_structure_entire_word_isomorph_or_matching_letter_pattern)* if they have the same pattern of letter repetitions. For example, both `ESTATE` and `DUELED` have pattern `abcdca`
```
ESTATE
DUELED
abcdca
```
because letters 1 and 6 are the same, letters 3 and 5 are the same, and nothing further. This also means the words are related by a substitution cipher, here with the matching `E <-> D, S <-> U, T <-> E, A <-> L`.
Write code that takes two words and checks whether they are isomorphs. Fewest bytes wins.
**Input:** Two non-empty strings of capital letters `A..Z`. If you wish, you can take these as a collection of two strings or as a single string with a separator.
**Output:** A consistent [Truthy value](http://meta.codegolf.stackexchange.com/q/2190/20260) for pairs that are isomorphs, and a consistent [Falsey value](http://meta.codegolf.stackexchange.com/q/2190/20260) if they are not. Strings of different lengths are valid inputs that are never isomorphs.
**Test cases:**
*True:*
```
ESTATE DUELED
DUELED ESTATE
XXX YYY
CBAABC DEFFED
RAMBUNCTIOUSLY THERMODYNAMICS
DISCRIMINATIVE SIMPLIFICATION
```
*False:*
```
SEE SAW
ANTS PANTS
BANANA SERENE
BANANA SENSES
AB CC
XXY XYY
ABCBACCBA ABCBACCAB
ABAB CD
```
Feel free to add more test cases you find useful.
**Leaderboard**
Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.
To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:
```
# Language Name, N bytes
```
where `N` is the size of your submission. If you improve your score, you *can* keep old scores in the headline, by striking them through. For instance:
```
# Ruby, <s>104</s> <s>101</s> 96 bytes
```
```
var QUESTION_ID=50472;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),e.has_more?getAnswers():process()}})}function shouldHaveHeading(e){var a=!1,r=e.body_markdown.split("\n");try{a|=/^#/.test(e.body_markdown),a|=["-","="].indexOf(r[1][0])>-1,a&=LANGUAGE_REG.test(e.body_markdown)}catch(n){}return a}function shouldHaveScore(e){var a=!1;try{a|=SIZE_REG.test(e.body_markdown.split("\n")[0])}catch(r){}return a}function getAuthorName(e){return e.owner.display_name}function process(){answers=answers.filter(shouldHaveScore).filter(shouldHaveHeading),answers.sort(function(e,a){var r=+(e.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0],n=+(a.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0];return r-n});var e={},a=1,r=null,n=1;answers.forEach(function(s){var t=s.body_markdown.split("\n")[0],o=jQuery("#answer-template").html(),l=(t.match(NUMBER_REG)[0],(t.match(SIZE_REG)||[0])[0]),c=t.match(LANGUAGE_REG)[1],i=getAuthorName(s);l!=r&&(n=a),r=l,++a,o=o.replace("{{PLACE}}",n+".").replace("{{NAME}}",i).replace("{{LANGUAGE}}",c).replace("{{SIZE}}",l).replace("{{LINK}}",s.share_link),o=jQuery(o),jQuery("#answers").append(o),e[c]=e[c]||{lang:c,user:i,size:l,link:s.share_link}});var s=[];for(var t in e)e.hasOwnProperty(t)&&s.push(e[t]);s.sort(function(e,a){return e.lang>a.lang?1:e.lang<a.lang?-1:0});for(var o=0;o<s.length;++o){var l=jQuery("#language-template").html(),t=s[o];l=l.replace("{{LANGUAGE}}",t.lang).replace("{{NAME}}",t.user).replace("{{SIZE}}",t.size).replace("{{LINK}}",t.link),l=jQuery(l),jQuery("#languages").append(l)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",answers=[],page=1;getAnswers();var SIZE_REG=/\d+(?=[^\d&]*(?:&lt;(?:s&gt;[^&]*&lt;\/s&gt;|[^&]+&gt;)[^\d&]*)*$)/,NUMBER_REG=/\d+/,LANGUAGE_REG=/^#*\s*([^,]+)/;
```
```
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
```
```
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"><div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table></div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table></div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table><table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table>
```
  
[Answer]
# J, 4 bytes
```
-:&=
```
Usage
```
   'THERMODYNAMICS' (-:&=) 'RAMBUNCTIOUSLY'  NB. parens are optional
1 
```
Explanation
* `=` with 1 argument creates an equality-table comparing the elements of the input and its nub.
```
='ESTATE' gives the binary matrix
= | E S T A T E    
--+------------
E | 1 0 0 0 0 1
S | 0 1 0 0 0 0
T | 0 0 1 0 1 0
A | 0 0 0 1 0 0
```
* `-:` with 2 arguments checks their equality (like `==` generally does). This works for different size matrices (or even different types) too.
* `f&g` applies g to both input separately and then applies f to the two results together so `x f&g y == f(g(x), g(y))`.
* So in our case we compare the two equality-tables.
[Try it online here.](http://tryj.tk/)
[Answer]
# K, 5 bytes
This has a delightfully elegant solution in K!
```
~/=:'
```
The "group" operator (monadic `=`) creates precisely the signature we want for word isomorphism; gathering vectors of the indices of each element of a vector, with the groups ordered by appearance:
```
  ="ABBAC"
(0 3
 1 2
 ,4)
  ="DCCDF"
(0 3
 1 2
 ,4)
```
Taking a pair of strings as a vector, we just need to apply group to each element (`=:'`) and then reduce with "match" (`~`), the deep-equality operator:
```
  ~/=:'("RAMBUNCTIOUSLY";"THERMODYNAMICS")
1
  ~/=:'("BANANA";"SERENE")
0
```
[Answer]
# Python 2, 41 bytes
```
f=lambda a,b:map(a.find,a)==map(b.find,b)
```
[Answer]
# CJam, 9 bytes
```
r_f#r_f#=
```
Prints `1` if the words are isomorphs and `0` if they're not.
Try it online in the [CJam interpreter](http://cjam.aditsu.net/#code=r_f%23r_f%23%3D&input=ESTATE%20DUELED).
### How it works
```
r    e# Read a whitespace separated token from STDIN.
_    e# Push a copy.
f#   e# Get the indexes of all characters from the first copy in the second.
r_f# e# Repeat for the second word.
=    e# Check for equality.
```
[Answer]
# JavaScript, ES7, ~~62 55 54 52~~ 51 bytes
```
f=(x,y,g=z=>[for(i of z)z.search(i)]+0)=>g(x)==g(y)
```
The logic is simple. I simply convert both the inputs into their corresponding character index values, convert that array into string and compare.
```
f=(x, y,                  // Create a function named f which takes two arguments x and y
   g=                     // There is a third default argument to f which equals to
     z=>                  // and arrow function which takes argument z
     [                    // Return this array which is created using array comprehension
      for(i of z)         // For each character of z
      z.search(i)         // Use the index of that character in z in place of the character
     ]+0                  // And finally type cast that array to a string
                          // Here, the array elements are automatically joined by a ','
                          // and appended by a 0.
                          // Its funny how JS type casts Array + Number to a string
   )=>                    // Now the body of function f starts
      g(x)==g(y)          // It simply returns if index map of x equals index map of y
          
```
Try the above code using the snippet below.
```
f=(x,y,g=z=>[for(i of z)z.search(i)]+0)=>g(x)==g(y)
// for cross browser testing, here is a slightly modified ES5 version of above function
if (!f) {
  function f(x, y) {
    function g(z) {
      var Z = [];
      for (var i = 0; i < z.length; i++) {
        Z[i] = z.search(z[i])
      }
      return Z + 0;
    }
    return g(x) == g(y);
  }
}
B.onclick=function() {
  O.innerHTML = f(D.value, E.value);
  
};
```
```
<pre>f(<input id=D />,<input id=E />)</pre><button id=B >Run</button>
<br>
<output id=O />
```
*2 bytes saved thanks to [@edc65](https://codegolf.stackexchange.com/users/21348/edc65)*
[Answer]
# Bash + coreutils, 38
```
[ `tr $@<<<$1``tr $2 $1<<<$2` = $2$1 ]
```
Note we are using the usual shell idea of truthy/falsy here - zero means SUCCESS or TRUE and non-zero means error or FALSE:
```
$ for t in "ESTATE DUELED" "DUELED ESTATE" "XXX YYY" "CBAABC DEFFED" "RAMBUNCTIOUSLY THERMODYNAMICS" "DISCRIMINATIVE SIMPLIFICATION" "SEE SAW" "ANTS PANTS" "BANANA SERENE" "BANANA SENSES" "AB CC" "XXY XYY" "ABCBACCBA ABCBACCAB"; do
> ./isomorph.sh $t
> echo $t $?
> done
ESTATE DUELED 0
DUELED ESTATE 0
XXX YYY 0
CBAABC DEFFED 0
RAMBUNCTIOUSLY THERMODYNAMICS 0
DISCRIMINATIVE SIMPLIFICATION 0
SEE SAW 1
ANTS PANTS 1
BANANA SERENE 1
BANANA SENSES 1
AB CC 1
XXY XYY 1
ABCBACCBA ABCBACCAB 1
$ 
```
[Answer]
# Haskell, ~~33~~ 29
# EDIT:
this is way too late, but i found this improvement using applicatives, that were added to prelude only in march 2015.
```
s%k=g s==g k
g s=(==)<$>s<*>s
```
Old version:
```
s%k=g s==g k
g s=[a==b|a<-s,b<-s]
```
the checking function is `(%)`
this works by generating for each string its "equality record": for each two indices i j, it records whether they have equal characters. the record is ordered so that the record for two indices i, j is always in the same place\*
and therefore checking the equality of the records would return whether or not the strings have the same pattern.
for example, the equality record of "ABC" is `[1,0,0,0,1,0,0,0,1]` (1 for true, 0 for false) - there is `True` where any index is compared with itself. anywhere else is a false. (skipping these checks might be more efficient, but is harder in terms of golfng)
\*if the strings are of the same length. otherwise it returns false just because the records are of different lengths
[Answer]
## R, 78
```
function(x,y)identical((g=function(z)match(a<-strsplit(z,"")[[1]],a))(x),g(y))
```
De-golfed:
```
word_to_num <- function(word) {
   chars <- strsplit(word,"")[[1]]
   match(chars, chars)
}
are_isomorph <- function(word1, word2) identical(word_to_num(word1), 
                                                 word_to_num(word2))
```
[Answer]
# Haskell, ~~45~~ 41 bytes
```
h l=map(`lookup`zip l[1..])l
x!y=h x==h y
```
Returns `True` or `False`, e.g `"ESTATE" ! "DUELED"` -> `True`.
Uses the map-char-to-first-index method as seen in many other answers. Association lists come in handy, because earlier entries trump. `"aba"` becomes `[(a,1),(b,2),(a,3)]` where `lookup` always fetches `a` -> `1`.
Edit: @Mauris found 4 bytes to save.
[Answer]
# Brainfuck, ~~169~~ ~~168~~ ~~162~~ ~~144~~ ~~140~~ ~~131~~ 130
Compatible with Alex Pankratov's [bff](http://swapped.cc/#!/bff) (brainfuck interpreter used on SPOJ and ideone) and Thomas Cort's [BFI](http://esoteric.sange.fi/brainfuck/impl/interp/BFI.c) (used on Anarchy Golf).
The expected input is two strings separated by a tab, with no newline after the second string. The output is `1` for isomorphs and `0` for non-isomorphs, which is convenient for checking results visually, although not the shortest option. (**Update:** shorter version with `\x01` and `\x00` as output and `\x00` as separator at the bottom of the answer.)
[Demonstration](http://ideone.com/nodXF7) on ideone.
```
,+
[
  -
  ---------
  >+<
  [
    >>-<
    [
      <
      [
        >+<
        <<<<-<+>>>>>-
      ]
      ++[->+]
      ->+[+<-]
      >[<<<<]
      <
    ]
    <[>+<-]
    +[->+]
    <->
    >>>
  ]
  >
  [
    [[-]<<<<<]
    >>>>
  ]
  <,+
]
>>>+>+
[
  [<->-]
  <[>>>>>]
  <<<<
]
-<[>]
+++++++[<+++++++>-]
<.
```
This problem turns out to be very nice for brainfuck.
The basic idea with indexing is to go backwards from the end of the current string prefix. If the character has not previously occurred, we can take the length of the string prefix. For example:
```
STATES
123255
```
The indexing in the code is actually slightly different but uses the same principle.
The memory layout is in blocks of 5:
```
0 0 0 0 0 0 c 0 i p 0 c 0 i p 0 c 0 i p 0 0 0 0
```
`c` stands for character, `i` for index, and `p` for previous (index). When the first string is being processed, all the `p` slots are zero. The cell to the left of `c` is used to hold a copy of the current character that we are trying to find the index of. The cell to the left of the current `i` is used to hold a `-1` for easy pointer navigation.
There are many conditions that need to be considered carefully. At the end, we check for isomorphs by comparing the `(i,p)` pairs, and we reach the cluster of zero cells to the left of the leftmost `(i,p)` pair if and only if the strings are isomorphs. Here is a commented version of the code to make it easier to follow:
```
,+
[                       while there is input
  -
  ---------
  >+<                   increment char (adjust later)
  [                     if not tab
    >>-<                set navigation flag
    [                   loop to find index
      <                 travel to copy
      [
        >+<             restore char
        <<<<-<+>>>>>-   compare chars and create copy
      ]
      ++[->+]           travel between navigation flags
      ->+[+<-]          increment index by 2 and go back
      >[<<<<]           proceed if not fallen off string
      <                 compare chars
    ]
    <[>+<-]             restore char (or no op)
    +[->+]              go back to navigation flag
    <->                 adjust char
    >>>                 alignment
  ]
  >
  [                     if tab
    [[-]<<<<<]          erase chars and go to beginning
    >>>>                alignment
  ]
  <,+
]
>>>+>+                  check string lengths and start loop
[
  [<->-]                compare indices
  <[>>>>>]              realign if not equal
  <<<<                  proceed
]
-<[>]                   cell to left is zero iff isomorphs
+++++++[<+++++++>-]
<.
```
**Update:**
Here is a version that prints `\x01` for isomorphs and `\x00` for non-isomorphs. This is arguably a more accurate interpretation of Truthy and Falsey for brainfuck, because of the way `[` and `]` work. The only difference is at the very end.
Additional: Now using `\x00` as a separator to save 10 bytes.
```
+
[
  -
  >+<
  [
    >>-<
    [
      <
      [
        >+<
        <<<<-<+>>>>>-
      ]
      ++[->+]
      ->+[+<-]
      >[<<<<]
      <
    ]
    <[>+<-]
    +[->+]
    <->
    >>>
  ]
  >
  [
    [[-]<<<<<]
    >>>>
  ]
  <,+
]
>>>+>+
[
  [<->-]
  <[>>>>>]
  <<<<
]
-<[>]
<+.
```
[Answer]
# JavaScript (ES6), 62
Using an aux function `h` that maps each word to an array containing the position of each letter in the word, for instance: PASS -> [1,2,3,3]. Return true if the function `h` applied the two words gives the same result. 
```
f=(a,b,h=w=>0+[for(c of(n=k=[],w))k[c]=k[c]||++n])=>h(b)==h(a)
// TEST
;[
// True
 ['ESTATE','DUELED']
,['DUELED','ESTATE']
,['XXX','YYY']
,['CBAABC','DEFFED']
,['RAMBUNCTIOUSLY','THERMODYNAMICS']
,['DISCRIMINATIVE','SIMPLIFICATION']
// False:
,['SEE','SAW']
,['ANTS','PANTS']
,['BANANA','SERENE']
,['BANANA','SENSES']
,['XXY','XYY']
,['ABCBACCBA','ABCBACCAB']
]
.forEach(t=>(f(t[0],t[1])?OK:KO).innerHTML+=t+'\n')
```
```
Ok<br>
<pre id=OK></pre><br>
KO<br>
<pre id=KO></pre>
```
[Answer]
# Ruby, 83 bytes
```
t=->x{y=0;z=?`;x.gsub!(y[0],z.succ!)while y=x.match(/[A-Z]/);x};f=->a,b{t[a]==t[b]}
```
It's a function `f` that takes two arguments and returns `true` or `false`.
Explanation:
```
test = -> str {
    y = nil  # we're just initializing this; it doesn't matter to what
             # this is the variable we use to store the `match' result
    z = '`'  # backtick is the ASCII character before `a'
    while y = str.match(/[A-Z]/) do  # while there is an uppercase letter in str
        str.gsub!(y[0], z.succ!)  # replace all instances of the uppercase letter
                                  # with the next unused lowercase letter
    end
    str  # return the new string
}
# self-explanatory
f=->a,b{test[a]==test[b]}
```
[Answer]
# Java, 107
```
(s,t)->java.util.Arrays.equals(s.chars().map(s::indexOf).toArray(),t.chars().map(t::indexOf).toArray())
```
Maps each character of `s` and `t` to its location, and checks for equality.
Expanded:
```
class Isomorphs {
    public static void main(String[] args) {
        java.util.function.BiFunction<String, String, Boolean> f =
            (s, t) -> java.util.Arrays.equals(
                                              s.chars().map(s::indexOf).toArray(),
                                              t.chars().map(t::indexOf).toArray()
                                             )
           ;
        System.out.println(f.apply("XXY", "XYY"));
    }
}
```
[Answer]
# Python 3, 85 bytes
```
f=lambda a,b:''.join(map(lambda g:dict(zip(a,b))[g],a))==b
g=lambda a,b:f(a,b)&f(b,a)
```
[Answer]
# Pyth, 9 bytes
```
qFmmxdkdQ
```
Takes input in the following form:
```
"ESTATE", "DUELED"
```
If that is not acceptable, the following code is 10 bytes:
```
qFmmxdkd.z
```
and uses this input form:
```
ESTATE
DUELED
```
Uses the index of char in string representation.
[Answer]
# Matlab, 50 bytes
```
f=@(s,t)isequal(bsxfun(@eq,s,s'),bsxfun(@eq,t,t'))
```
The function is defined as anonymous to save some space.
Example:
```
>> f=@(s,t)isequal(bsxfun(@eq,s,s'),bsxfun(@eq,t,t'));
>> f('ESTATE','DUELED')
ans =
     1
>> f('ANTS','PANTS')
ans =
     0
```
[Answer]
# Octave, 26 bytes
```
@(s,t)isequal(s==s',t==t')
```
[Answer]
# Ruby, 31 bytes
```
->a{!!a.uniq!{|s|s.tr s,'a-z'}}
```
A Proc that takes an array of strings and checks whether any are isomorphic to each other. `tr s,'a-z'` with these arguments normalizes a string `s` by replacing each letter with the nth letter in the alphabet, where `n` is the greatest index with which that letter appears in the string. For example, `estate` becomes `fbedef`, as does `dueled`.
[Answer]
# [05AB1E](https://github.com/Adriandmen/05AB1E), 6 bytes
```
εæδË}Ë
```
[Try it online!](https://tio.run/##MzBNTDJM/f//3NbDy85tOdxde7j7//9odRfPYOcgT19PP8cQzzBXdR0F9WBP3wAfTzdPZ6CIv596LAA "05AB1E – Try It Online")
Takes input as a list: `['ESTATE', 'DUELED']`
**Explanations:**
```
    εæδË}Ë   Full program
    ε        Apply on each
     æ         Powerset
      δË       For each generated substring: 1 if all equal, 0 otherwise
        }    End for each
         Ë   1 if all equal, 0 otherwise
```
[Answer]
# [APL (Dyalog)](https://www.dyalog.com/), ~~5~~ 4 bytes
-1 thanks to ngn's hint.
Anonymous tacit prefix function which takes a list of two strings as argument.
```
≡.⍳⍨
```
[Try it Online!](https://tio.run/##XU69CsIwEN59CrdM@g6X6xUPmrQkqTajILoIuvoCgkPBV3Bz9436InpJSwcJIff9Xb799bw63Pbny@n7PQ735/B4rYf@M/RvwUtFPkAgtVRFSxUVanGcx1lMXNd1QsQYM0INoDGlqCynlAOjW4uB69ZXUbSwIWfqIlowjH7czB4dG7YQeJt@9WyaiktGIWqbPZ6yALuMwAYvsMlvIjRYOclBjiz9c9bT6AMtGHEqn/p0U3lprgHlqnkW86iMqUL9AA "APL (Dyalog Unicode) – Try It Online")
This is an inner product, but instead of the usual `+` and `×` it uses
`≡` identicalness 
`.` and 
`⍳` the **ɩ**ndex (the first occurrence of each element)
`⍨` with the entire two-element list of words used as both arguments
If we call the words `A` and `B`, then we can derive the previous solution as follows:
`≡.⍳⍨ A B`  
`A B ≡.⍳ A B`  
`(A⍳A) ≡ (B⍳B)`  
`(⍳⍨A) ≡ (⍳⍨B)`  
`≡/ ⍳⍨¨ A B`
### Previous solution
Anonymous tacit prefix function which takes a list of two strings as argument.
```
≡/⍳⍨¨
```
[Try it online!](https://tio.run/##XU5LCsIwEN17CndZiWeYTKc40KSlSbVZFqRuBN16AcGF4BXcufcGHqUX0UlaupAQMu83ed35uNpfuuPp8P32w/Ux3J7r4f4e7q/PS5ilIufBk1qqrKGCMrXo53EWI9e2rRAhhIRQA2iMKcrzKVWD0Y1Fz2XjiiCa31BtyixYMIxu3MwOazZswfM2/urYVAXnjEKUNnkcJQF2CYH1TmCV3khosHKig2qy9M9ZR6MPtGDEqXzs007lpbkGlKvmWcyjMqYy9QM "APL (Dyalog Unicode) – Try It Online")
`≡` identicalness 
`/` across
`⍳` the **ɩ**ndex (the first occurrence of each element…)
`⍨` selfie (…in itself)
`¨` of each
[Answer]
# Mathematica, 46 bytes
```
Equal@@Values@*PositionIndex/@Characters@{##}&
```
[Answer]
# Ruby, 50 bytes
30 bytes shorter ruby code. Written before I took a look at the solutions, checks for each character of both strings whether the index of that character's first occurence matches; ie. transforms a string to its normalized form `01121` etc and compares those.
```
->x,y{g=->z{z.chars.map{|c|z=~/#{c}/}};g[x]==g[y]}
```
Test cases on [ideone](https://ideone.com/0tfSD3) As an additional bonus, this breaks ideone's code highlighting.
[Answer]
## PCRE, 84 bytes
```
^((.)(?=.+ (\3.|)(.))(?=((?=(\2|)?+.* \3\4(\7?(?(?=.*+\6)(?!\4).|\4))).)+ ))+. \3..$ 
```
Subject should be two space-separated words, as in the OP. Here's a cursory explanation:
> 
> For each letter X in the first word:
> 
> 
> 
> > 
> > Look ahead to the second word and establish back references to recall how far along we are as well as the letter Y in the second word corresponding to X.
> > 
> > 
> > For each letter Z past the current position in the first word:
> > 
> > 
> > 
> > > 
> > > Establish similar back references as above.
> > > 
> > > 
> > > Look ahead to the corresponding letter in the second word and check if Z = X then match a Y, otherwise match a letter that isn't Y.
> > > 
> > > 
> > > 
> > 
> > 
> > 
> 
> 
> This iteration can end once we've matched up until the penultimate letter in the first word. At this point, since no further validation is necessary, all that remains is to test that the words are of equal length (the back reference containing accumulating substrings of the second word is always behind by 1 letter).
> 
> 
> 
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), 4 bytes
```
ĠṢ)E
```
[Try it online!](https://tio.run/##RU47bsMwDN11Cg5ZeoZOFEWjRCzZMOXWOkCWwBfImiXXKDpnCjq06NhexL2ISsMBCuLxffCGdzzM86nWn9fl8@2B6/L1vnzcfs/Xx@/LzmhvKLWyZswMYeSWg9sIttBN0wSlFEce0RMEbhrrDBj9mChLN2pbID/xELtQEkYhdUGUBomSMMszg0rsW2mEzHbJKVuELw5TVujX7zwmO1AeOPG/S8rq0AORzSgw2Qzb4JEMcFfoLVs74Q8 "Jelly – Try It Online")
[Another 4 byte version](https://tio.run/##RU47bsMwDN11Cg5ZeoZOFEWjRCzZMOXWOkCXIhfImqWXKQIkyNDP2JPYF1FpOEBBPL4P3vDeXg@HY63z99dyOT9wnX9u8@d1OX08/r7vjPaGUitrxswQRm45uI1gC900TVBKceQRPUHgprHOgNGPibJ0o7YF8hMPsQslYRRSF0RpkCgJszwzqMS@lUbIbJecskX44jBlhX79zmOyA@WBE/@7pKwOPRDZjAKTzbANHskAd4XesrUT/gA)
## How they work
```
ĠṢ)E - Main link. Takes [A, B] on the left
  )  - Over each string S in the input:
Ġ    -   Group the indices of S by it's values
 Ṣ   -   Sort the lists of indices
   E - Are both equal?
ẹⱮ)E - Main link. Takes [A, B] on the left
  )  - Over each string S in the input:
 Ɱ   -   For each character C in S:
ẹ    -     Get the indices of C in S
   E - Are both equal?
```
[Answer]
# [Vyxal](https://github.com/Vyxal/Vyxal), 7 bytes
```
ƛUẊv≈;≈
```
[Try it Online!](https://vyxal.pythonanywhere.com/#WyIiLCIiLCLGm1Xhuop24omIO+KJiCIsIiIsIltcIkRJU0NSSU1JTkFUSVZFXCIsXCJTSU1QTElGSUNBVElPTlwiXSJd)
```
ƛ    ;≈ # Same upon...
  Ẋ     # Cartesian product of...
 U      # Uniquified value
        # And (implicit) value
   v≈   # For each, same?
```
[Answer]
# [BQN](https://mlochbaum.github.io/BQN/), 3 bytes[SBCS](https://github.com/mlochbaum/BQN/blob/master/commentary/sbcs.bqn)
```
≡○⊐
```
[Run online!](https://mlochbaum.github.io/BQN/try.html#code=RiDihpAg4omh4peL4oqQCgo+4ouI4p+cKEbCtCnCqOKfqCJFU1RBVEUi4oC/IkRVRUxFRCIKIkRVRUxFRCLigL8iRVNUQVRFIgoiWFhYIuKAvyJZWVkiCiJDQkFBQkMi4oC/IkRFRkZFRCIKIlJBTUJVTkNUSU9VU0xZIuKAvyJUSEVSTU9EWU5BTUlDUyIKIkRJU0NSSU1JTkFUSVZFIuKAvyJTSU1QTElGSUNBVElPTiIKIlNFRSLigL8iU0FXIgoiQU5UUyLigL8iUEFOVFMiCiJCQU5BTkEi4oC/IlNFUkVORSIKIkJBTkFOQSLigL8iU0VOU0VTIgoiQUIi4oC/IkNDIgoiWFhZIuKAvyJYWVkiCiJBQkNCQUNDQkEi4oC/IkFCQ0JBQ0NBQiIKIkFCQUIi4oC/IkNEIuKfqQ==)
The builtin *Classify* `⊐` gets the pattern of letter repetitions for a given string as a vector of non-negative integers. All that's left to do is to compare the two results for equality.
```
⊐ "ESTATE"
# ⟨ 0 1 2 3 2 0 ⟩
⊐ "DUELED"
# ⟨ 0 1 2 3 2 0 ⟩
(⊐ "ESTATE") ≡ (⊐ "DUELED")
# 1
"ESTATE" ≡○⊐ "DUELED"
# 1
```
[Answer]
# [Husk](https://github.com/barbuz/Husk), 5 bytes
```
¤=´×=
```
[Try it online!](https://tio.run/##yygtzv7//9AS20NbDk@3/f//v5JrcIhjiKvSfyWXUFcfVxclAA "Husk – Try It Online")
### Explanation
```
       -- implicit input A, B (strings aka character lists)       | "ab" "12"
¤=     -- apply the following function to A & B, then compare:    | [1,0,0,1] == [1,0,0,1] -> 1
  ´×   --   Cartesian product with itself under                   | ["aa","ba","ab","bb"] ["11","21","12","22"]
    =  --   equality                                              | [ 1  , 0  , 0  , 1  ] [ 1  , 0  , 0  , 1  ]
```
[Answer]
# [Husk](https://github.com/barbuz/Husk), ~~5~~ 4 bytes
```
Ë´Ṫ=
```
[Try it online!](https://tio.run/##yygtzv7//3D3oS0Pd66y/f//f7SSa3CIY4irko6SS6irj6uLUiwA "Husk – Try It Online")
-1 byte from Leo using ბიმო's answer.
## Explanation
```
Ë´Ṫ=
Ë    check if all the elements are equal by the following predicate:
 ´Ṫ  cartesian product with self
   = by equality
```
[Answer]
# [Thunno 2](https://github.com/Thunno/Thunno2), 6 [bytes](https://github.com/Thunno/Thunno2/blob/main/docs/codepage.md)
```
ıʠ€ạ;ạ
```
[Try it online!](https://Not-Thonnu.github.io/run#aGVhZGVyPSZjb2RlPSVDNCVCMSVDQSVBMCVFMiU4MiVBQyVFMSVCQSVBMSUzQiVFMSVCQSVBMSZmb290ZXI9JmlucHV0PSUyMkVTVEFURSUyMiUyQyUyMCUyMkRVRUxFRCUyMiZmbGFncz0=)
#### Explanation
```
ıʠ€ạ;ạ  # Implicit input 
ı   ;   # Map:
 ʠ      #  Powerset of the string
  €     #  For each one:
   ạ    #   Check if all equal
     ạ  # Check if all equal
        # Implicit output
```
[Answer]
# [Nekomata](https://github.com/AlephAlpha/Nekomata) + `-e`, 5 bytes
```
ŤuŤᵐů
```
[Attempt This Online!](https://ato.pxeger.com/run?1=XVC9TsMwEBYrj8CEPCc76_lyEZZip4odiBV1KKhdqsLQ9j3YWToECSEkJh4hL8HGm3D-6YIsy_f93PmzX9-f1tvn3eqw-hxFuRPFtSjXYnl6Ox425c3HPB3n6ff7Zf6a9g-P-0yffi6uRkHWgSNRiKqnhiqxvBzPZXEWAzcMAxPe-4hQAkgMXVTXuasDLXuDTrW9bTxr7pY63VbegFZo02RlsVNaGXDqLtxqlV40qlbIRGuix1IU4D4iMM4yXMQzEBIMr-Cgjgz954yl5APJGDGHD3mGHJ6TS0DezOWazUlJXfyg9Ed_)
Takes input as a list of two strings.
```
ŤuŤᵐů
Ť       Transpose; ["ESTATE","DUELED"] -> ["ED","SU","TE","AL","TE","ED"]
 u      Uniquify; ["ED","SU","TE","AL","TE","ED"] -> ["ED","SU","TE","AL"]
  Ť     Transpose; ["ED","SU","TE","AL"] -> ["ESTA","DUEL"]
   ᵐů   Check that neither string contains duplicate characters
```
]