green on run for single epoch
This commit is contained in:
parent
1b51405f02
commit
afbd9d9bdf
2 changed files with 115 additions and 44 deletions
|
@ -127,44 +127,66 @@ export const decomposeRules = (epoch: epochType, phones: {[key: string]: phoneTy
|
||||||
return featureBundle;
|
return featureBundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isPhonemeBoundByRule = (phonemeFeatures, ruleFeatures) => {
|
||||||
|
if (!ruleFeatures) return true;
|
||||||
|
const match = ruleFeatures.filter((ruleFeature, index) => {
|
||||||
|
const phoneme = phonemeFeatures[index].features;
|
||||||
|
return Object.entries(ruleFeature).reduce((bool, entry) => {
|
||||||
|
if (!bool) return false;
|
||||||
|
if (!phoneme[entry[0]] && !entry[1]) return true;
|
||||||
|
if (phoneme[entry[0]] !== entry[1]) return false;
|
||||||
|
return true;
|
||||||
|
}, true);
|
||||||
|
})
|
||||||
|
return match.length === ruleFeatures.length ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const swapPhoneme = (phoneme, newFeatures, features) => {
|
||||||
|
const newPhonemeFeatures = Object.entries(newFeatures).reduce((newPhoneme, [newFeature, newValue]) => {
|
||||||
|
return { ...newPhoneme, [newFeature]: newValue }
|
||||||
|
}, {...phoneme.features})
|
||||||
|
const newPhonemeCandidates = Object.entries(newPhonemeFeatures).map(([newFeature, newValue]) => {
|
||||||
|
return features[newFeature][newValue ? 'positive': 'negative']
|
||||||
|
})
|
||||||
|
const newPhoneme = newPhonemeCandidates.reduce((candidates, value, index, array) => {
|
||||||
|
return candidates.filter(candidate => value.map(val => val.grapheme).includes(candidate.grapheme))
|
||||||
|
}, newPhonemeCandidates[newPhonemeCandidates.length - 1])
|
||||||
|
return newPhoneme[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const transformLexeme = (lexemeBundle, rule, features) => {
|
||||||
|
const {pre, post, position} = rule.environment;
|
||||||
|
const newLexeme = lexemeBundle.reduce((newLexeme, phoneme, index) => {
|
||||||
|
if ( index < pre.length || index >= lexemeBundle.length - post.length ) return [...newLexeme, phoneme];
|
||||||
|
if (!isPhonemeBoundByRule(lexemeBundle.slice(index - pre.length, index), pre)) return [...newLexeme, phoneme];
|
||||||
|
if (!isPhonemeBoundByRule([phoneme], rule.environment.position)) return [...newLexeme, phoneme];
|
||||||
|
if (!isPhonemeBoundByRule(lexemeBundle.slice(index, index + post.length), post)) return [...newLexeme, phoneme];
|
||||||
|
const newPhoneme = swapPhoneme(phoneme, rule.newFeatures[0], features);
|
||||||
|
return [...newLexeme, newPhoneme];
|
||||||
|
}, [])
|
||||||
|
return newLexeme;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export const run = (state: stateType, action: resultsAction): stateType => {
|
export const run = (state: stateType, action: resultsAction): stateType => {
|
||||||
|
|
||||||
// for each epoch
|
// for each epoch
|
||||||
// TODO iterate through each epoch
|
// TODO iterate through each epoch
|
||||||
let ruleBundle = state.epochs[0].changes;
|
const epoch = state.epochs[0];
|
||||||
|
const phones = state.phones;
|
||||||
// for each rule in epoch
|
const lexicon = state.lexicon;
|
||||||
ruleBundle = ruleBundle.map(rule => decomposeRule(rule))
|
const features = state.features;
|
||||||
// parse rule into feature bundles for
|
const ruleBundle = decomposeRules(epoch, phones);
|
||||||
// environment
|
const lexiconBundle = lexicon.map(lexeme => findFeaturesFromLexeme(phones, lexeme.lexeme))
|
||||||
// pre-target
|
|
||||||
// post-target
|
|
||||||
// target
|
|
||||||
// mutation
|
|
||||||
// for each item in lexicon
|
|
||||||
// match targets in environments
|
|
||||||
// mutate target
|
|
||||||
// temporarily store lexical item
|
|
||||||
// store lexical items in resulting epoch
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ruleBundle.map(rule => {
|
const results = lexiconBundle.map(lexemeBundle => {
|
||||||
rule.forEach(position => {
|
return ruleBundle.reduce((lexeme, rule) => {
|
||||||
console.log(position)
|
return transformLexeme(lexeme, rule, features);
|
||||||
})
|
}, lexemeBundle)
|
||||||
})
|
})
|
||||||
|
|
||||||
let featurePhoneBundle = state.lexicon.map(lexeme => findFeaturesFromLexeme(state.phones, lexeme))
|
const stringifiedResults = results.map(lexemeBundle => {
|
||||||
|
return Object.entries(lexemeBundle).map(phoneme => phoneme[1].grapheme).join('')
|
||||||
console.log(featurePhoneBundle)
|
})
|
||||||
ruleBundle.forEach(rule => {
|
return {...state, results: { pass: state.epochs[0].name, results: stringifiedResults } }
|
||||||
featurePhoneBundle.map(featurePhone => {
|
|
||||||
// if (findRules(featurePhone, )
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
let results = [];
|
|
||||||
return {...state, results: { pass: state.epochs[0].name, results } }
|
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import { stateReducer } from './reducer';
|
import { stateReducer } from './reducer';
|
||||||
import { initState } from './reducer.init';
|
import { initState } from './reducer.init';
|
||||||
import { decomposeRules } from './reducer.results';
|
import { decomposeRules, transformLexeme } from './reducer.results';
|
||||||
|
|
||||||
describe('Results', () => {
|
describe('Results', () => {
|
||||||
let state = {};
|
let state = {};
|
||||||
|
@ -35,17 +35,66 @@ describe('Results', () => {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
expect(decomposeRules(epoch, phones)).toStrictEqual(result);
|
expect(decomposeRules(epoch, phones)).toStrictEqual(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('expect transform lexeme to apply rule to lexeme', () => {
|
||||||
|
const lexemeBundle = [
|
||||||
|
{
|
||||||
|
grapheme: 'a',
|
||||||
|
features: {
|
||||||
|
sonorant: true,
|
||||||
|
back: true,
|
||||||
|
low: true,
|
||||||
|
high: false,
|
||||||
|
rounded: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
grapheme: 'n',
|
||||||
|
features: { sonorant: true, nasal: true, occlusive: true, coronal: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
grapheme: 't',
|
||||||
|
features: { occlusive: true, coronal: true, obstruent: true }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
grapheme: 'a',
|
||||||
|
features: {
|
||||||
|
sonorant: true,
|
||||||
|
back: true,
|
||||||
|
low: true,
|
||||||
|
high: false,
|
||||||
|
rounded: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const resultsLexeme = [...lexemeBundle]
|
||||||
|
resultsLexeme[2] = lexemeBundle[1]
|
||||||
|
|
||||||
|
const rule = {
|
||||||
|
environment: {
|
||||||
|
pre: [ { sonorant: true, nasal: true, occlusive: true, coronal: true } ],
|
||||||
|
position: [ { occlusive: true, nasal: false } ],
|
||||||
|
post: []
|
||||||
|
},
|
||||||
|
newFeatures: [ { occlusive: true, nasal: true } ]
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(transformLexeme(lexemeBundle, rule, initState().features)).toEqual(resultsLexeme)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// it('results returned from first sound change rule', () => {
|
|
||||||
// const action = {type: 'RUN'};
|
it('results returned from first sound change rule', () => {
|
||||||
// state = initState(0)
|
const action = {type: 'RUN'};
|
||||||
// expect(stateReducer(state, action).results).toEqual({
|
state = initState(0)
|
||||||
// pass: 'epoch 1',
|
expect(stateReducer(state, action).results).toEqual({
|
||||||
// results: [
|
pass: 'epoch 1',
|
||||||
// 'anna', 'anat', 'anət', 'anna', 'tan', 'ənna'
|
results: [
|
||||||
// ]
|
'anna', 'anat', 'anət', 'anna', 'tan', 'ənna'
|
||||||
// })
|
]
|
||||||
// });
|
})
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
Loading…
Reference in a new issue