green on run for single epoch

This commit is contained in:
Sorrel Bri 2020-02-16 00:48:36 -08:00
parent 1b51405f02
commit afbd9d9bdf
2 changed files with 115 additions and 44 deletions

View file

@ -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 } }
} }

View file

@ -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'
// }) ]
// }); })
});
}); });